From f9d4e1d6aeadc76c93252357d0bd62f56cea548b Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Mon, 12 Mar 2018 08:39:32 +1300 Subject: [PATCH] Ancestry of food. Seeds -> Planting -> Seeds -> Planting (#1550) * Add seed ancestry, and seeds.finished_at * Plantings and seeds produce each other * Permissions for seeds actions * View update, for seed actions, and planting ancestry * Routes for seeds * Scopes for harvests * Spec updates for seeds * Removed in-line style * Add seed ancestry, and seeds.finished_at * Plantings and seeds produce each other * Permissions for seeds actions * View update, for seed actions, and planting ancestry * Routes for seeds * Scopes for harvests * Spec updates for seeds * Moved finishable to a concern * Seeds.finished_at * rubocop fixes * Made seeds sown migration the most recent * Specs for home page * Only show current seeds on home page * Seeds appear for logged in or not * Buttons to mark seeds finished * JS for marking seeds finished * Some actions only appear if seed or planting is active * Fixed up display of home page * Fixed typo in admin members#index * Tidying up actions on all the things * Harvest description in #index * Truncate garden description if long * Updated link label in view spec * Show planted_from always, becuase it might be a parent seed * find correct link in spec adding photos to garden * fixed spec finding link to edit garden * Better harvest description truncation * Helping spec find the edit button * specs for the home page * Re-instate crops js, but in the correct file now * Fixed link to garden in actions * Tweaking mobile view --- app/assets/javascripts/crops.js.coffee | 39 ++++++++ app/assets/javascripts/finish_seed.js.coffee | 19 ++++ app/assets/javascripts/seeds.js.coffee | 38 -------- app/controllers/plantings_controller.rb | 3 + app/controllers/seeds_controller.rb | 26 +++--- app/helpers/harvests_helper.rb | 9 +- app/helpers/photos_helper.rb | 39 ++++++++ app/models/ability.rb | 7 +- app/models/concerns/finishable.rb | 12 +++ app/models/harvest.rb | 7 ++ app/models/planting.rb | 9 +- app/models/seed.rb | 5 + app/views/admin/members/index.html.haml | 2 +- app/views/crops/_actions.html.haml | 8 ++ app/views/crops/_image_with_popover.html.haml | 2 +- app/views/crops/_thumbnail.html.haml | 8 +- app/views/crops/show.html.haml | 9 +- app/views/gardens/_actions.html.haml | 55 +++++------ app/views/gardens/_nav.haml | 13 +-- app/views/gardens/_overview.html.haml | 12 +-- app/views/gardens/index.html.haml | 6 +- app/views/gardens/show.html.haml | 24 ++--- app/views/harvests/_actions.html.haml | 6 ++ app/views/harvests/_card.html.haml | 14 +-- app/views/harvests/_image_with_popover.haml | 9 ++ app/views/harvests/_list.html.haml | 11 +++ app/views/harvests/_popover.html.haml | 3 + app/views/harvests/_thumbnail.html.haml | 1 + app/views/harvests/show.html.haml | 8 +- app/views/home/_crops.html.haml | 33 +------ app/views/home/_discuss.html.haml | 2 +- app/views/home/_harvests.html.haml | 3 + app/views/home/_members.html.haml | 4 +- app/views/home/_plantings.html.haml | 3 + app/views/home/_seeds.html.haml | 34 +++---- app/views/home/index.html.haml | 26 +++++- app/views/layouts/application.html.haml | 4 +- app/views/photos/_actions.html.haml | 6 ++ app/views/photos/_item_photos.haml | 24 +++-- app/views/photos/_thumbnail.html.haml | 22 +++-- app/views/photos/show.html.haml | 10 +- app/views/plantings/_actions.html.haml | 37 +++----- app/views/plantings/_card.html.haml | 22 +---- app/views/plantings/_descendants.html.haml | 14 +++ app/views/plantings/_form.html.haml | 12 ++- app/views/plantings/_harvests.html.haml | 15 +-- .../plantings/_image_with_popover.html.haml | 4 +- app/views/plantings/_list.html.haml | 6 +- app/views/plantings/show.html.haml | 43 +++++---- app/views/seeds/_actions.html.haml | 26 +++--- app/views/seeds/_card.html.haml | 32 +++++++ app/views/seeds/_descendants.html.haml | 13 +++ app/views/seeds/_form.html.haml | 26 +++++- app/views/seeds/_thumbnail.html.haml | 45 +++------ app/views/seeds/index.html.haml | 2 +- app/views/seeds/show.html.haml | 93 ++++++++++--------- app/views/shared/buttons/_add_photo.haml | 4 + app/views/shared/buttons/_delete.haml | 4 + app/views/shared/buttons/_edit.haml | 3 + .../shared/buttons/_finish_planting.html.haml | 5 + app/views/shared/buttons/_finish_seeds.haml | 5 + .../shared/buttons/_harvest_planting.haml | 4 + app/views/shared/buttons/_save_seeds.haml | 4 + config/routes.rb | 5 +- db/migrate/20180213005731_seed_usage.rb | 22 +++++ db/schema.rb | 8 +- spec/controllers/plantings_controller_spec.rb | 8 ++ spec/controllers/seeds_controller_spec.rb | 21 ++++- spec/factories/seeds.rb | 8 ++ spec/features/gardens/actions_spec.rb | 84 +++++++++++++++++ spec/features/gardens_spec.rb | 6 +- .../features/harvests/browse_harvests_spec.rb | 17 ++-- .../harvests/harvesting_a_crop_spec.rb | 4 +- spec/features/home/home_spec.rb | 84 +++++++++++++++++ spec/features/photos/new_photo_spec.rb | 4 +- spec/features/seeds/misc_seeds_spec.rb | 4 +- spec/models/planting_spec.rb | 16 ++++ spec/models/seed_spec.rb | 34 +++++++ spec/views/gardens/show.html.haml_spec.rb | 2 +- spec/views/home/_crops.html.haml_spec.rb | 26 ------ spec/views/plantings/show.html.haml_spec.rb | 5 +- 81 files changed, 901 insertions(+), 451 deletions(-) create mode 100644 app/assets/javascripts/crops.js.coffee create mode 100644 app/assets/javascripts/finish_seed.js.coffee create mode 100644 app/helpers/photos_helper.rb create mode 100644 app/models/concerns/finishable.rb create mode 100644 app/views/crops/_actions.html.haml create mode 100644 app/views/harvests/_actions.html.haml create mode 100644 app/views/harvests/_image_with_popover.haml create mode 100644 app/views/harvests/_list.html.haml create mode 100644 app/views/harvests/_popover.html.haml create mode 100644 app/views/home/_harvests.html.haml create mode 100644 app/views/home/_plantings.html.haml create mode 100644 app/views/photos/_actions.html.haml create mode 100644 app/views/plantings/_descendants.html.haml create mode 100644 app/views/seeds/_card.html.haml create mode 100644 app/views/seeds/_descendants.html.haml create mode 100644 app/views/shared/buttons/_add_photo.haml create mode 100644 app/views/shared/buttons/_delete.haml create mode 100644 app/views/shared/buttons/_edit.haml create mode 100644 app/views/shared/buttons/_finish_planting.html.haml create mode 100644 app/views/shared/buttons/_finish_seeds.haml create mode 100644 app/views/shared/buttons/_harvest_planting.haml create mode 100644 app/views/shared/buttons/_save_seeds.haml create mode 100644 db/migrate/20180213005731_seed_usage.rb create mode 100644 spec/features/gardens/actions_spec.rb create mode 100644 spec/features/home/home_spec.rb delete mode 100644 spec/views/home/_crops.html.haml_spec.rb diff --git a/app/assets/javascripts/crops.js.coffee b/app/assets/javascripts/crops.js.coffee new file mode 100644 index 000000000..6a0a27123 --- /dev/null +++ b/app/assets/javascripts/crops.js.coffee @@ -0,0 +1,39 @@ +jQuery -> + $('#add-sci_name-row').css("display", "inline-block") + $('#remove-sci_name-row').css("display", "inline-block") + $("#add-alt_name-row").css("display", "inline-block") + $("#remove-alt_name-row").css("display", "inline-block") + +-$ -> + sci_template = "
Scientific name of crop.
" + + sci_index = $('#scientific_names .template').length + 1 + + $('#add-sci_name-row').click -> + compiled_input = $(sci_template.split("INDEX").join(sci_index)) + $('#scientific_names').append(compiled_input) + sci_index = sci_index + 1 + + $('#remove-sci_name-row').click -> + if (sci_index > 2) + sci_index = sci_index - 1 + tmp = 'sci_template[' + sci_index + ']' + element = document.getElementById(tmp) + element.remove() + + alt_template = "
Alternate name of crop.
" + + alt_index = $('#alternate_names .template').length + 1 + + $('#add-alt_name-row').click -> + compiled_input = $(alt_template.split("INDEX").join(alt_index)) + $('#alternate_names').append(compiled_input) + alt_index = alt_index + 1 + + $('#remove-alt_name-row').click -> + if (alt_index > 2) + alt_index = alt_index - 1 + tmp = 'alt_template[' + alt_index + ']' + element = document.getElementById(tmp) + console.log("%s",tmp) + element.remove() \ No newline at end of file diff --git a/app/assets/javascripts/finish_seed.js.coffee b/app/assets/javascripts/finish_seed.js.coffee new file mode 100644 index 000000000..53a878963 --- /dev/null +++ b/app/assets/javascripts/finish_seed.js.coffee @@ -0,0 +1,19 @@ +# Clears the finished at date field when +# a seed is marked unfinished, and +# repopulates the field with a cached value +# marking unfinished is undone. + +jQuery -> + previousValue = '' + $('#seed_finished').on('click', -> + finished = $('#seed_finished_at') + if @checked + if previousValue.length + date = previousValue + finished.val(date) + else + finished.trigger('focus') + else + previousValue = finished.val() + finished.val('') + ) diff --git a/app/assets/javascripts/seeds.js.coffee b/app/assets/javascripts/seeds.js.coffee index 6cbfb9eb1..ab5b73462 100644 --- a/app/assets/javascripts/seeds.js.coffee +++ b/app/assets/javascripts/seeds.js.coffee @@ -4,41 +4,3 @@ jQuery -> $('.add-datepicker').datepicker('format' : 'yyyy-mm-dd') - $('#add-sci_name-row').css("display", "inline-block") - $('#remove-sci_name-row').css("display", "inline-block") - $("#add-alt_name-row").css("display", "inline-block") - $("#remove-alt_name-row").css("display", "inline-block") - -$ -> - sci_template = "
Scientific name of crop.
" - - sci_index = $('#scientific_names .template').length + 1 - - $('#add-sci_name-row').click -> - compiled_input = $(sci_template.split("INDEX").join(sci_index)) - $('#scientific_names').append(compiled_input) - sci_index = sci_index + 1 - - $('#remove-sci_name-row').click -> - if (sci_index > 2) - sci_index = sci_index - 1 - tmp = 'sci_template[' + sci_index + ']' - element = document.getElementById(tmp) - element.remove() - - alt_template = "
Alternate name of crop.
" - - alt_index = $('#alternate_names .template').length + 1 - - $('#add-alt_name-row').click -> - compiled_input = $(alt_template.split("INDEX").join(alt_index)) - $('#alternate_names').append(compiled_input) - alt_index = alt_index + 1 - - $('#remove-alt_name-row').click -> - if (alt_index > 2) - alt_index = alt_index - 1 - tmp = 'alt_template[' + alt_index + ']' - element = document.getElementById(tmp) - console.log("%s",tmp) - element.remove() diff --git a/app/controllers/plantings_controller.rb b/app/controllers/plantings_controller.rb index f50083213..f6da9d076 100644 --- a/app/controllers/plantings_controller.rb +++ b/app/controllers/plantings_controller.rb @@ -37,6 +37,7 @@ class PlantingsController < ApplicationController def new @planting = Planting.new(planted_at: Time.zone.today) + @seed = Seed.find_by(slug: params[:seed_id]) if params[:seed_id] # using find_by_id here because it returns nil, unlike find @crop = Crop.approved.find_by(id: params[:crop_id]) || Crop.new @@ -54,6 +55,7 @@ class PlantingsController < ApplicationController def create @planting = Planting.new(planting_params) @planting.owner = current_member + @planting.crop = @planting.parent_seed.crop if @planting.parent_seed.present? @planting.save! respond_with @planting end @@ -82,6 +84,7 @@ class PlantingsController < ApplicationController params[:planted_at] = parse_date(params[:planted_at]) if params[:planted_at] params.require(:planting).permit( :crop_id, :description, :garden_id, :planted_at, + :parent_seed_id, :quantity, :sunniness, :planted_from, :finished, :finished_at ) diff --git a/app/controllers/seeds_controller.rb b/app/controllers/seeds_controller.rb index 12445877e..b18e6090a 100644 --- a/app/controllers/seeds_controller.rb +++ b/app/controllers/seeds_controller.rb @@ -16,44 +16,37 @@ class SeedsController < ApplicationController respond_with(@seeds) end - # GET /seeds/1 - # GET /seeds/1.json def show @photos = @seed.photos.includes(:owner).order(created_at: :desc).paginate(page: params[:page]) respond_with(@seed) end - # GET /seeds/new - # GET /seeds/new.json def new @seed = Seed.new - # using find_by_id here because it returns nil, unlike find - @crop = Crop.find_or_initialize_by(id: params[:crop_id]) + if params[:planting_id] + @planting = Planting.find_by(slug: params[:planting_id]) + else + @crop = Crop.find_or_initialize_by(id: params[:crop_id]) + end respond_with(@seed) end - # GET /seeds/1/edit def edit; end - # POST /seeds - # POST /seeds.json def create @seed = Seed.new(seed_params) @seed.owner = current_member + @seed.crop = @seed.parent_planting.crop if @seed.parent_planting flash[:notice] = "Successfully added #{@seed.crop} seed to your stash." if @seed.save respond_with(@seed) end - # PUT /seeds/1 - # PUT /seeds/1.json def update flash[:notice] = 'Seed was successfully updated.' if @seed.update(seed_params) respond_with(@seed) end - # DELETE /seeds/1 - # DELETE /seeds/1.json def destroy @seed.destroy respond_with(@seed) @@ -64,8 +57,11 @@ class SeedsController < ApplicationController def seed_params params.require(:seed).permit( :crop_id, :description, :quantity, :plant_before, - :days_until_maturity_min, :days_until_maturity_max, :organic, :gmo, - :heirloom, :tradable_to, :slug + :parent_planting_id, + :days_until_maturity_min, :days_until_maturity_max, + :organic, :gmo, + :heirloom, :tradable_to, :slug, + :finished, :finished_at ) end diff --git a/app/helpers/harvests_helper.rb b/app/helpers/harvests_helper.rb index 14277817b..10ed30888 100644 --- a/app/helpers/harvests_helper.rb +++ b/app/helpers/harvests_helper.rb @@ -28,7 +28,12 @@ module HarvestsHelper end def display_harvest_description(harvest) - return "No description provided." if harvest.description.nil? - harvest.description + if harvest.description.nil? + "no description provided." + else + truncate(harvest.description, length: 50, separator: ' ', omission: '... ') do + link_to "Read more", harvest_path(harvest) + end + end end end diff --git a/app/helpers/photos_helper.rb b/app/helpers/photos_helper.rb new file mode 100644 index 000000000..50064f328 --- /dev/null +++ b/app/helpers/photos_helper.rb @@ -0,0 +1,39 @@ +module PhotosHelper + def crop_image_path(crop) + if crop.default_photo.present? + crop.default_photo.thumbnail_url + else + default_image + end + end + + def planting_image_path(planting) + if planting.photos.present? + planting.photos.first.thumbnail_url + else + default_image + end + end + + def harvest_image_path(harvest) + if harvest.photos.present? + harvest.photos.first.thumbnail_url + else + default_image + end + end + + def seed_image_path(seed) + if seed.default_photo + seed.default_photo.thumbnail_url + else + default_image + end + end + + private + + def default_image + 'placeholder_150.png' + end +end diff --git a/app/models/ability.rb b/app/models/ability.rb index 89a304257..4fd14340e 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -111,9 +111,12 @@ class Ability can :update, Photo, owner_id: member.id can :destroy, Photo, owner_id: member.id - can :create, Seed - can :update, Seed, owner_id: member.id + can :create, Seed + can :update, Seed, owner_id: member.id can :destroy, Seed, owner_id: member.id + can :create, Seed, owner_id: member.id, parent_planting: { owner_id: member.id } + can :update, Seed, owner_id: member.id, parent_planting: { owner_id: member.id } + can :destroy, Seed, owner_id: member.id, parent_planting: { owner_id: member.id } # following/unfollowing permissions can :create, Follow diff --git a/app/models/concerns/finishable.rb b/app/models/concerns/finishable.rb new file mode 100644 index 000000000..42fa4e734 --- /dev/null +++ b/app/models/concerns/finishable.rb @@ -0,0 +1,12 @@ +module Finishable + extend ActiveSupport::Concern + + included do + scope :finished, -> { where(finished: true) } + scope :current, -> { where.not(finished: true) } + + def active? + !finished + end + end +end diff --git a/app/models/harvest.rb b/app/models/harvest.rb index 6bb9aa048..9bc4195b4 100644 --- a/app/models/harvest.rb +++ b/app/models/harvest.rb @@ -40,6 +40,13 @@ class Harvest < ActiveRecord::Base ## ## Scopes default_scope { joins(:owner) } # Ensures owner exists + scope :interesting, -> { has_photos.one_per_owner } + scope :recent, -> { order(created_at: :desc) } + scope :one_per_owner, lambda { + joins("JOIN members m ON (m.id=harvests.owner_id) + LEFT OUTER JOIN harvests h2 + ON (m.id=h2.owner_id AND harvests.id < h2.id)").where("h2 IS NULL") + } ## ## Validations diff --git a/app/models/planting.rb b/app/models/planting.rb index 6fd4aec17..e358a6bb4 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -1,6 +1,7 @@ class Planting < ActiveRecord::Base extend FriendlyId include PhotoCapable + include Finishable friendly_id :planting_slug, use: %i(slugged finders) # Constants @@ -20,11 +21,15 @@ class Planting < ActiveRecord::Base belongs_to :crop, counter_cache: true has_many :harvests, dependent: :destroy + # + # Ancestry of food + belongs_to :parent_seed, class_name: 'Seed', foreign_key: 'parent_seed_id' # parent + has_many :child_seeds, class_name: 'Seed', + foreign_key: 'parent_planting_id', dependent: :nullify # children + ## ## Scopes default_scope { joins(:owner) } # Ensures the owner still exists - scope :finished, -> { where(finished: true) } - scope :current, -> { where(finished: false) } scope :interesting, -> { has_photos.one_per_owner } scope :recent, -> { order(created_at: :desc) } scope :one_per_owner, lambda { diff --git a/app/models/seed.rb b/app/models/seed.rb index 7abae922c..63c88a47c 100644 --- a/app/models/seed.rb +++ b/app/models/seed.rb @@ -1,6 +1,7 @@ class Seed < ActiveRecord::Base extend FriendlyId include PhotoCapable + include Finishable friendly_id :seed_slug, use: %i(slugged finders) TRADABLE_TO_VALUES = %w(nowhere locally nationally internationally).freeze @@ -13,6 +14,10 @@ class Seed < ActiveRecord::Base belongs_to :crop belongs_to :owner, class_name: 'Member', foreign_key: 'owner_id', counter_cache: true + belongs_to :parent_planting, class_name: 'Planting', foreign_key: 'parent_planting_id' # parent + has_many :child_plantings, class_name: 'Planting', + foreign_key: 'parent_seed_id', dependent: :nullify # children + # # Validations validates :crop, approved: true diff --git a/app/views/admin/members/index.html.haml b/app/views/admin/members/index.html.haml index 2408a55db..d91b1f8a1 100644 --- a/app/views/admin/members/index.html.haml +++ b/app/views/admin/members/index.html.haml @@ -11,5 +11,5 @@ %th - @members.each do |member| %tr - %td= ember.login_name + %td= member.login_name %td= member.email diff --git a/app/views/crops/_actions.html.haml b/app/views/crops/_actions.html.haml new file mode 100644 index 000000000..26f083d7b --- /dev/null +++ b/app/views/crops/_actions.html.haml @@ -0,0 +1,8 @@ +- if can? :create, Planting + = link_to "Plant this", new_planting_path(crop_id: crop.id), class: 'btn btn-default' + +- if can? :create, Harvest + = link_to "Harvest this", new_harvest_path(crop_id: crop.id), class: 'btn btn-default' + +- if can? :create, Seed + = link_to 'Add seeds to stash', new_seed_path(params: { crop_id: crop.id }), class: 'btn btn-default' diff --git a/app/views/crops/_image_with_popover.html.haml b/app/views/crops/_image_with_popover.html.haml index 6744ccfe1..a8ce256bd 100644 --- a/app/views/crops/_image_with_popover.html.haml +++ b/app/views/crops/_image_with_popover.html.haml @@ -1,5 +1,5 @@ - cache crop do - = link_to image_tag(crop.default_photo.present? ? crop.default_photo.thumbnail_url : 'placeholder_150.png', + = link_to image_tag(crop_image_path(crop), alt: crop.name, class: 'image-responsive crop-image'), crop.name, rel: "popover", diff --git a/app/views/crops/_thumbnail.html.haml b/app/views/crops/_thumbnail.html.haml index 1926b31d8..c83a1a0c6 100644 --- a/app/views/crops/_thumbnail.html.haml +++ b/app/views/crops/_thumbnail.html.haml @@ -1,7 +1,7 @@ -.thumbnail - .crop-thumbnail - - if crop - - cache cache_key_for(Crop, crop.id) do +- cache cache_key_for(Crop, crop.id) do + .thumbnail + .crop-thumbnail + - if crop = link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), alt: crop.name, class: 'img'), crop diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index cd9751469..7700501fa 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -15,14 +15,7 @@ - if @crop.approved? - content_for :buttonbar do - - if can? :create, Planting - = link_to "Plant this", new_planting_path(crop_id: @crop.id), class: 'btn btn-default' - - - if can? :create, Harvest - = link_to "Harvest this", new_harvest_path(crop_id: @crop.id), class: 'btn btn-default' - - - if can? :create, Seed - = link_to 'Add seeds to stash', new_seed_path(params: { crop_id: @crop.id }), class: 'btn btn-default' + = render 'crops/actions', crop: @crop .row .col-md-9 diff --git a/app/views/gardens/_actions.html.haml b/app/views/gardens/_actions.html.haml index ecf434911..a5187991e 100644 --- a/app/views/gardens/_actions.html.haml +++ b/app/views/gardens/_actions.html.haml @@ -1,28 +1,29 @@ -- if can?(:edit, garden) || can?(:delete, garden) - - if can? :edit, garden - - if garden.active - = link_to new_planting_path(garden_id: garden.id), class: 'btn btn-primary' do - %span.glyphicon.glyphicon-grain{ title: "Plant" } - Plant something - = link_to "Mark as inactive", garden_path(garden, garden: { active: 0 }), - method: :put, class: 'btn btn-default', - data: { confirm: 'All plantings associated with this garden will be marked as finished. Are you sure?' } - - else - = link_to "Mark as active", garden_path(garden, garden: { active: 1 }), - method: :put, - class: 'btn btn-default' - = link_to edit_garden_path(garden), class: 'btn btn-default', id: 'edit_garden_link' do - %span.glyphicon.glyphicon-pencil{ title: "Edit garden" } - Edit +.garden-actions + - if can?(:edit, garden) + .btn-group + - if garden.active + = link_to new_planting_path(garden_id: garden.id), class: 'btn btn-default btn-xs' do + %span.glyphicon.glyphicon-grain{ title: "Plant" } + Plant something + = link_to "Mark as inactive", garden_path(garden, garden: { active: 0 }), + method: :put, class: 'btn btn-default btn-xs', + data: { confirm: 'All plantings associated with this garden will be marked as finished. Are you sure?' } + - else + = link_to "Mark as active", garden_path(garden, garden: { active: 1 }), + method: :put + = render 'shared/buttons/edit', path: edit_garden_path(garden) + + - if can?(:edit, garden) && can?(:create, Photo) + = link_to new_photo_path(type: "garden", id: garden.id), + class: 'btn btn-default btn-xs' do + %span.glyphicon.glyphicon-camera{ title: "Add photo" } + Add photo + - if can?(:destroy, garden) - = link_to garden, - method: :delete, - data: { confirm: 'All plantings associated with this garden will also be deleted. Are you sure?' }, - class: 'btn btn-default', id: 'delete_garden_link' do - %span.glyphicon.glyphicon-trash{ title: "Delete" } - Delete - - if can?(:edit, garden) && can?(:create, Photo) - = link_to new_photo_path(type: "garden", id: garden.id), - class: 'btn btn-primary' do - %span.glyphicon.glyphicon-camera{ title: "Add Photo" } - Add Photo + .pull-right + = link_to garden_path(garden), + method: :delete, + data: { confirm: 'All plantings associated with this garden will also be deleted. Are you sure?' }, + class: 'btn btn-default btn-xs', id: 'delete_garden_link' do + %span.glyphicon.glyphicon-trash{ title: "Delete" } + Delete diff --git a/app/views/gardens/_nav.haml b/app/views/gardens/_nav.haml index 82ae83086..36c828b87 100644 --- a/app/views/gardens/_nav.haml +++ b/app/views/gardens/_nav.haml @@ -4,12 +4,7 @@ = link_to "Everyone's gardens", gardens_path, class: 'btn btn-default' - - = link_to gardens_active_tickbox_path(@owner, show_all) do - = check_box_tag 'active', 'all', show_all - include in-active - -- if can?(:create, Garden) - = link_to 'Add a garden', new_garden_path, class: 'btn btn-primary' -- unless current_member - = render partial: 'shared/signin_signup', locals: { to: 'add a new garden' } + - if can?(:create, Garden) + = link_to 'Add a garden', new_garden_path, class: 'btn btn-default' + - unless current_member + = render 'shared/signin_signup', to: 'add a new garden' diff --git a/app/views/gardens/_overview.html.haml b/app/views/gardens/_overview.html.haml index 644115d16..b8f9ce54a 100644 --- a/app/views/gardens/_overview.html.haml +++ b/app/views/gardens/_overview.html.haml @@ -1,9 +1,7 @@ - .panel.panel-success .panel-heading %h3.panel-title = link_to garden.name, garden_path(garden) - .panel-body .row .col-md-2.col-xs-12.garden-info @@ -11,15 +9,17 @@ .col-md-12.col-xs-6 = render 'gardens/photo', garden: garden .col-md-12.col-xs-6 - = render 'gardens/actions', garden: garden + = display_garden_description(garden) .col-md-10 .row - if garden.plantings.current.size.positive? - garden.plantings.current.includes(:crop).each do |planting| .col-md-2.col-sm-6.col-xs-6 .hover-wrapper - .text= render 'plantings/actions', planting: planting + .text + = render 'plantings/actions', planting: planting = render partial: "plantings/thumbnail", locals: { planting: planting } - else - no plantings - -# .panel-footer + .col-md-2.col-sm-6.col-xs-6 no plantings + - if can?(:edit, garden) + .panel-footer= render 'gardens/actions', garden: garden diff --git a/app/views/gardens/index.html.haml b/app/views/gardens/index.html.haml index 4cf4f0705..a09de73ff 100644 --- a/app/views/gardens/index.html.haml +++ b/app/views/gardens/index.html.haml @@ -1,6 +1,10 @@ - content_for :title, @owner ? "#{@owner}'s gardens" : "Everyone's gardens" -= render 'nav', owner: @owner, show_all: @show_all += render 'nav' + += link_to gardens_active_tickbox_path(@owner, @show_all) do + = check_box_tag 'active', 'all', @show_all + include in-active .pagination = page_entries_info @gardens diff --git a/app/views/gardens/show.html.haml b/app/views/gardens/show.html.haml index 9d4158a00..8b45b0b16 100644 --- a/app/views/gardens/show.html.haml +++ b/app/views/gardens/show.html.haml @@ -16,7 +16,8 @@ .row .col-md-9 - %p.btn-group= render 'gardens/actions', garden: @garden + = render 'gardens/actions', garden: @garden + - unless @garden.active .alert.alert-warning @@ -26,20 +27,21 @@ to plant something in this garden. %div - :growstuff_markdown - #{strip_tags @garden.description} - - unless @garden.description - .row-fluid - %p No description available yet. + %p + :growstuff_markdown + #{strip_tags @garden.description} + - unless @garden.description + .row-fluid + %p No description available yet. - - if can? :edit, @garden - %p - Why not - = link_to 'tell us more.', edit_garden_path(@garden) + - if can? :edit, @garden + %p + Why not + = link_to 'tell us more.', edit_garden_path(@garden) %h3 Garden timeline .row - = timeline garden_timeline_path(@garden), adapter: "google" + .col-md-12= timeline garden_timeline_path(@garden), adapter: "google" %h3 Current plantings in garden .row diff --git a/app/views/harvests/_actions.html.haml b/app/views/harvests/_actions.html.haml new file mode 100644 index 000000000..5a2f1febc --- /dev/null +++ b/app/views/harvests/_actions.html.haml @@ -0,0 +1,6 @@ +- if can?(:edit, harvest) || can?(:destroy, harvest) + .btn-group.harvest-actions + - if can? :edit, harvest + = render 'shared/buttons/edit', path: edit_harvest_path(harvest) + - if can? :destroy, harvest + .pull-right= render 'shared/buttons/delete', path: harvest_path(harvest) diff --git a/app/views/harvests/_card.html.haml b/app/views/harvests/_card.html.haml index e82d53725..1a12128b0 100644 --- a/app/views/harvests/_card.html.haml +++ b/app/views/harvests/_card.html.haml @@ -21,9 +21,11 @@ %dd= display_quantity(harvest) %dt Harvest date : %dd= harvest.harvested_at - .panel-footer - %dt Description - %dd.truncate - = display_harvest_description(harvest) - = if harvest.description.present? - - link_to "Read more", harvest_path(harvest) + %dd Notes: + %dt=display_harvest_description(harvest) + - if harvest.planting.present? + %dt Harvested from + %dd= link_to(harvest.planting, planting_path(harvest.planting)) + .row + .col-md-12 + = render 'harvests/actions', harvest: harvest diff --git a/app/views/harvests/_image_with_popover.haml b/app/views/harvests/_image_with_popover.haml new file mode 100644 index 000000000..ebfb187f6 --- /dev/null +++ b/app/views/harvests/_image_with_popover.haml @@ -0,0 +1,9 @@ += link_to image_tag(harvest_image_path(harvest), + alt: harvest.to_s, + class: 'image-responsive crop-image'), + harvest, + rel: "popover", + 'data-trigger': 'hover', + 'data-title': harvest.to_s, + 'data-content': render('harvests/popover', harvest: harvest), + 'data-html': true diff --git a/app/views/harvests/_list.html.haml b/app/views/harvests/_list.html.haml new file mode 100644 index 000000000..bb0178238 --- /dev/null +++ b/app/views/harvests/_list.html.haml @@ -0,0 +1,11 @@ +- harvests.each do |h| + - cache h do + .row + .col-md-3.col-xs-4{ style: 'padding-bottom: 6px' } + = render 'harvests/image_with_popover', harvest: h + .col-md-9.col-xs-4 + = link_to h.crop, crop_path(h.crop) + %br/ + %small + %i + = h.owner.location diff --git a/app/views/harvests/_popover.html.haml b/app/views/harvests/_popover.html.haml new file mode 100644 index 000000000..508413918 --- /dev/null +++ b/app/views/harvests/_popover.html.haml @@ -0,0 +1,3 @@ +%p + %small + = harvest.harvested_at diff --git a/app/views/harvests/_thumbnail.html.haml b/app/views/harvests/_thumbnail.html.haml index 9a9beac0c..d7fec2a7a 100644 --- a/app/views/harvests/_thumbnail.html.haml +++ b/app/views/harvests/_thumbnail.html.haml @@ -7,3 +7,4 @@ .harvestinfo .harvest-name = link_to harvest, harvest + = I18n.l(harvest.harvested_at.to_date) diff --git a/app/views/harvests/show.html.haml b/app/views/harvests/show.html.haml index 2f9114084..a584389fe 100644 --- a/app/views/harvests/show.html.haml +++ b/app/views/harvests/show.html.haml @@ -32,13 +32,7 @@ %b Quantity: = display_quantity(@harvest) - - if can?(:edit, @harvest) || can?(:destroy, @harvest) - %p - - if can? :edit, @harvest - = link_to 'Edit', edit_harvest_path(@harvest), class: 'btn btn-default btn-xs' - - if can? :destroy, @harvest - = link_to 'Delete', @harvest, method: :delete, data: { confirm: 'Are you sure?' }, - class: 'btn btn-default btn-xs' + = render 'harvests/actions', harvest: @harvest .col-md-6 = render partial: "crops/index_card", locals: { crop: @harvest.crop } diff --git a/app/views/home/_crops.html.haml b/app/views/home/_crops.html.haml index 6f881dc32..edec779e0 100644 --- a/app/views/home/_crops.html.haml +++ b/app/views/home/_crops.html.haml @@ -1,28 +1,5 @@ -.row - .col-md-8 - - cache cache_key_for(Crop, 'interesting'), expires_in: 1.day do - %h2= t('.our_crops') - .hidden-xs - - Crop.interesting.includes(:scientific_names, :photos).first(8).each do |c| - .col-md-3 - = render partial: 'crops/thumbnail', locals: { crop: c } - .visible-xs - - Crop.interesting.includes(:scientific_names, :photos).first(3).each do |c| - .col-md-3 - = render partial: 'crops/thumbnail', locals: { crop: c } - - .col-md-4.hidden-xs - - cache cache_key_for(Planting) do - %h2= t('.recently_planted') - = render 'plantings/list', plantings: Planting.includes(:owner, :photos).interesting.recent.first(6) - -.row - .col-md-12 - - cache cache_key_for(Crop, 'recent') do - %p{ style: 'margin-top: 11.25px' } - %strong - #{t('.recently_added')}: - != Crop.recent.limit(12).map { |c| link_to(c, c) }.join(", ") - - %p.text-right - = link_to "#{t('.view_all')} »", crops_path +- cache cache_key_for(Crop, 'interesting'), expires_in: 1.day do + .row + %h2= t('.our_crops') + - Crop.interesting.includes(:scientific_names, :photos).limit(7).each do |c| + .col-md-4.col-xs-4= render 'crops/thumbnail', crop: c diff --git a/app/views/home/_discuss.html.haml b/app/views/home/_discuss.html.haml index 36cc1d0f9..0ec3077e1 100644 --- a/app/views/home/_discuss.html.haml +++ b/app/views/home/_discuss.html.haml @@ -1,6 +1,6 @@ %h2= t('.discussion') -- posts = Post.limit(6) +- posts = Post.order(created_at: :desc).limit(6) - if posts = render "posts/summary", posts: posts, howmany: 6 diff --git a/app/views/home/_harvests.html.haml b/app/views/home/_harvests.html.haml new file mode 100644 index 000000000..d4c2a1117 --- /dev/null +++ b/app/views/home/_harvests.html.haml @@ -0,0 +1,3 @@ +- cache cache_key_for(Harvest) do + %h2 Recently Harvested + = render 'harvests/list', harvests: Harvest.includes(:crop, :owner, :photos).has_photos.recent.first(5) diff --git a/app/views/home/_members.html.haml b/app/views/home/_members.html.haml index 0c786ca7b..c3a4392ba 100644 --- a/app/views/home/_members.html.haml +++ b/app/views/home/_members.html.haml @@ -1,13 +1,13 @@ - cache cache_key_for(Member) do .hidden-xs - - members = Member.interesting.first(6) + - members = Member.includes(plantings: :crop).interesting.first(6) - if members.present? %section %h2= t('.title') .member-cards - members.each do |m| - = render partial: "members/thumbnail", locals: { member: m } + = render "members/thumbnail", member: m %p.text-right = link_to "#{t('.view_all')} »", members_path diff --git a/app/views/home/_plantings.html.haml b/app/views/home/_plantings.html.haml new file mode 100644 index 000000000..bfaa4a422 --- /dev/null +++ b/app/views/home/_plantings.html.haml @@ -0,0 +1,3 @@ +- cache cache_key_for(Planting, 'home'), expires_in: 1.day do + %h2= t('.recently_planted') + = render 'plantings/list', plantings: Planting.includes(:crop, garden: :owner).has_photos.recent.first(5) diff --git a/app/views/home/_seeds.html.haml b/app/views/home/_seeds.html.haml index 7469b90b0..3f018994a 100644 --- a/app/views/home/_seeds.html.haml +++ b/app/views/home/_seeds.html.haml @@ -1,21 +1,21 @@ - cache cache_key_for(Seed, 'interesting'), expires_in: 1.day do %h2= t('.title') .row - .col-md-8 - - Seed.includes(:owner, crop: :photos).order(created_at: :desc).interesting.first(6).each do |seed| - .col-md-3 - .thumbnail - - cache cache_key_for(Crop, seed.id) do - = link_to image_tag((seed.default_photo ? seed.default_photo.thumbnail_url : 'placeholder_150.png'), - alt: seed.crop.name, class: 'img'), - seed - .seedinfo - = link_to seed.crop.name, seed - .trade-to - %p= seed.owner.location - %p - Will trade to: - %br/ - #{seed.tradable_to} + - Seed.current.tradable.order(created_at: :desc).limit(6).each do |seed| + .col-md-2.col-xs-4 + .thumbnail + - cache cache_key_for(Crop, seed.id) do + = link_to image_tag(seed_image_path(seed), + alt: seed.crop.name, class: 'img'), + seed + .seedinfo + = link_to seed.crop.name, seed + .trade-to + %p= seed.owner.location + %p + Will trade to: + %br/ + #{seed.tradable_to} + %p.text-right - = link_to "#{t('.view_all')} »", seeds_path += link_to "#{t('.view_all')} »", seeds_path diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 655fbd3fc..80502c3f5 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -18,8 +18,26 @@ .visible-xs = render partial: 'blurb' - = render partial: 'crops' - = render partial: 'seeds' - = render partial: 'members' - = render partial: 'discuss' + .row + .col-md-6 + = render partial: 'crops' + .col-md-3 + = render partial: 'plantings' + .col-md-3 + = render partial: 'harvests' + .col-md-12 + - cache cache_key_for(Crop, 'recent') do + %p{ style: 'margin-top: 11.25px' } + %strong + #{t('.recently_added')}: + != Crop.recent.limit(30).map { |c| link_to(c, c) }.join(", ") + %p.text-right + = link_to "#{t('home.crops.view_all')} »", crops_path + .row + .col-md-12 + = render partial: 'seeds' + = render partial: 'members' + .row + .col-md-12 + = render partial: 'discuss' diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 3dcf02c39..2c0f6b9bb 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -15,9 +15,7 @@ %small= yield(:subtitle) - if content_for?(:buttonbar) - %p - .btn-group - = yield(:buttonbar) + .btn-group.layout-actions= yield(:buttonbar) = render partial: "shared/flash_messages", flash: flash = yield diff --git a/app/views/photos/_actions.html.haml b/app/views/photos/_actions.html.haml new file mode 100644 index 000000000..878d985ef --- /dev/null +++ b/app/views/photos/_actions.html.haml @@ -0,0 +1,6 @@ +- if can?(:edit, @photo) && can?(:destroy, @photo) + %p.photo-actions + - if can?(:edit, @photo) + = render 'shared/buttons/edit', path: edit_photo_path(@photo) + - if can?(:destroy, @photo) + = render 'shared/buttons/delete', path: photo_path(@photo) diff --git a/app/views/photos/_item_photos.haml b/app/views/photos/_item_photos.haml index 679871680..f0642c336 100644 --- a/app/views/photos/_item_photos.haml +++ b/app/views/photos/_item_photos.haml @@ -1,16 +1,14 @@ +%h2 Photos + - if photos.size.positive? || (can?(:edit, item) && can?(:create, Photo)) - %h2 Photos - if photos.size.positive? + = page_entries_info photos + = will_paginate photos .row - .pagination - = page_entries_info photos - = will_paginate photos - .row - - photos.each do |photo| - .col-md-2.six-across= render 'photos/thumbnail', photo: photo - - if can?(:create, Photo) && can?(:edit, item) - .col-md-2 - .thumbnail - = link_to new_photo_path(type: type, id: item.id), class: 'btn btn-primary' do - %span.glyphicon.glyphicon-camera{ title: "Add photo" } - Add photo + - photos.each do |photo| + .col-xs-6.col-md-3.six-across= render 'photos/thumbnail', photo: photo + +- if can?(:create, Photo) && can?(:edit, item) + = link_to new_photo_path(type: type, id: item.id), class: 'btn btn-primary' do + %span.glyphicon.glyphicon-camera{ title: "Add photo" } + Add photo diff --git a/app/views/photos/_thumbnail.html.haml b/app/views/photos/_thumbnail.html.haml index 03a1f0c4c..3be4a26d6 100644 --- a/app/views/photos/_thumbnail.html.haml +++ b/app/views/photos/_thumbnail.html.haml @@ -1,10 +1,12 @@ -.thumbnail.photo-thumbnail - = link_to image_tag(photo.thumbnail_url, alt: photo.title, class: 'img img-responsive'), photo - .text - %p - = link_to photo.title, photo - %br/ - %small - %i - by - = link_to photo.owner, photo.owner +.thumbnail + .photo-thumbnail + = link_to image_tag(photo.thumbnail_url, alt: photo.title, class: 'img img-responsive'), photo + .text + %p + = link_to photo.title, photo + %br/ + %small + %i + by + = link_to photo.owner, photo.owner + = I18n.l(photo.created_at.to_date) diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index 7e52a11e9..3758883b6 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -12,15 +12,7 @@ %p= image_tag(@photo.fullsize_url, alt: @photo.title, class: 'img img-responsive') .col-md-4 - %p - - if can? :destroy, @photo - = link_to @photo, method: :delete, - data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-trash{ title: "Delete" } - - - if can? :edit, @photo - = link_to edit_photo_path(@photo), class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-pencil{ title: "Edit" } + = render 'photos/actions', photo: @photo %p %strong Posted by: = link_to @photo.owner, @photo.owner diff --git a/app/views/plantings/_actions.html.haml b/app/views/plantings/_actions.html.haml index b2c2d5f98..87eddc8cf 100644 --- a/app/views/plantings/_actions.html.haml +++ b/app/views/plantings/_actions.html.haml @@ -1,27 +1,12 @@ -- if can?(:edit, planting) || can?(:destroy, planting) - - if can? :edit, planting - = link_to edit_planting_path(planting), class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-pencil{ title: "Edit" } - Edit +- if can?(:edit, planting) + .btn-group.planting-actions + = render 'shared/buttons/edit', path: edit_planting_path(planting) + = render 'shared/buttons/add_photo', path: new_photo_path(id: planting.id, type: 'planting') + + - if planting.active? + = render 'shared/buttons/finish_planting', planting: planting + = render 'shared/buttons/harvest_planting', planting: planting + = render 'shared/buttons/save_seeds', planting: planting + - if can? :destroy, planting - = link_to planting, method: :delete, - data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-trash{ title: "Delete" } - Delete - - - unless planting.finished - = link_to planting_path(planting, planting: { finished: 1 }), - method: :put, class: 'btn btn-default btn-xs append-date' do - - %span.glyphicon.glyphicon-ok{ title: "Finished" } - Mark as finished - - - if can? :edit, planting - = link_to new_planting_harvest_path(planting), class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-leaf{ title: "Harvest" } - Harvest - - - if can?(:edit, planting) && can?(:create, Photo) - = link_to new_photo_path(id: planting.id, type: 'planting'), class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-camera{ title: "Add photo" } - Add photo + = render 'shared/buttons/delete', path: planting diff --git a/app/views/plantings/_card.html.haml b/app/views/plantings/_card.html.haml index a5469461a..bb6d77347 100644 --- a/app/views/plantings/_card.html.haml +++ b/app/views/plantings/_card.html.haml @@ -35,24 +35,6 @@ %dt Finish expected: %dd= planting.finish_predicted_at if planting.finish_predicted_at.present? - %p= render 'plantings/progress', planting: planting, show_explanation: true - - = link_to 'Details', planting_path(planting), - class: 'btn btn-default btn-xs' - - - if can?(:edit, planting) && can?(:create, Harvest) - = link_to 'Harvest', new_planting_harvest_path(planting), - class: 'btn btn-default btn-xs' - - - if can?(:edit, planting) && !planting.finished - = link_to "Mark as finished", - planting_path(planting, planting: { finished: 1 }), - method: :put, - class: 'btn btn-default btn-xs append-date' - - - if can? :destroy, planting - = link_to planting, method: :delete, - data: { confirm: 'Are you sure?' }, - class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-trash{ title: "Delete" } + .row + .col-md-12= render 'plantings/actions', planting: planting diff --git a/app/views/plantings/_descendants.html.haml b/app/views/plantings/_descendants.html.haml new file mode 100644 index 000000000..27e81c6b8 --- /dev/null +++ b/app/views/plantings/_descendants.html.haml @@ -0,0 +1,14 @@ +%h2 Seeds saved from this planting + +- if planting.child_seeds.size.positive? + .row + - planting.child_seeds.each do |seed| + .col-xs-6.col-sm-4.col-md-3 + = render 'seeds/thumbnail', seed: seed +- else + %p No seeds saved + +- if planting.active? && can?(:create, Seed) && can?(:edit, planting) + = link_to new_planting_seed_path(planting), class: 'btn btn-primary' do + %span.glyphicon.glyphicon-heart{ title: "Add photo" } + Save seeds diff --git a/app/views/plantings/_form.html.haml b/app/views/plantings/_form.html.haml index 4b0d979b6..874b5329b 100644 --- a/app/views/plantings/_form.html.haml +++ b/app/views/plantings/_form.html.haml @@ -13,10 +13,14 @@ .form-group.required = f.label :crop, 'What did you plant?', class: 'control-label col-md-2' .col-md-8 - = auto_suggest @planting, :crop, class: 'form-control', default: @crop - %span.help-inline - Can't find what you're looking for? - = link_to "Request new crops.", new_crop_path + - if @seed.present? + = link_to @seed, seed_path(@seed) + = f.hidden_field :parent_seed_id, value: @seed.id + - else + = auto_suggest @planting, :crop, class: 'form-control', default: @crop + %span.help-inline + Can't find what you're looking for? + = link_to "Request new crops.", new_crop_path .form-group.required = f.label :garden_id, 'Where did you plant it?', class: 'control-label col-md-2' .col-md-8 diff --git a/app/views/plantings/_harvests.html.haml b/app/views/plantings/_harvests.html.haml index 5edf14a3d..a845e980e 100644 --- a/app/views/plantings/_harvests.html.haml +++ b/app/views/plantings/_harvests.html.haml @@ -1,12 +1,13 @@ +%h2 Harvests - if planting.harvests.empty? - %p no harvests yet + %p No harvests - else .row - planting.harvests.order(created_at: :desc).includes(:crop).each do |harvest| - .col-xs-6.col-md-2 + .col-xs-6.col-sm-4.col-md-3 = render 'harvests/thumbnail', harvest: harvest - - if can? :edit, planting - .col-xs-6.col-md-2 - = link_to new_planting_harvest_path(planting), class: 'btn btn-primary' do - %span.glyphicon.glyphicon-leaf{ title: "Harvest" } - Harvest + +- if planting.active? && can?(:edit, planting) + = link_to new_planting_harvest_path(planting), class: 'btn btn-primary' do + %span.glyphicon.glyphicon-leaf{ title: "Harvest" } + Harvest diff --git a/app/views/plantings/_image_with_popover.html.haml b/app/views/plantings/_image_with_popover.html.haml index d958a9d41..70bfc1836 100644 --- a/app/views/plantings/_image_with_popover.html.haml +++ b/app/views/plantings/_image_with_popover.html.haml @@ -1,10 +1,10 @@ - cache planting do - = link_to image_tag(planting.photos.present? ? planting.photos.first.thumbnail_url : 'placeholder_150.png', + = link_to image_tag(planting_image_path(planting), alt: planting.to_s, class: 'image-responsive crop-image'), planting, rel: "popover", 'data-trigger': 'hover', 'data-title': planting.to_s, - 'data-content': render(partial: 'plantings/popover', locals: { planting: planting }), + 'data-content': render('plantings/popover', planting: planting), 'data-html': true diff --git a/app/views/plantings/_list.html.haml b/app/views/plantings/_list.html.haml index cf678c8a6..02901cdcd 100644 --- a/app/views/plantings/_list.html.haml +++ b/app/views/plantings/_list.html.haml @@ -1,9 +1,9 @@ - plantings.each do |p| - cache p do .row - .col-md-3{ style: 'padding-bottom: 6px' } + .col-md-3.col-xs-4{ style: 'padding-bottom: 6px' } = render partial: 'plantings/image_with_popover', locals: { planting: p } - .col-md-9 + .col-md-9.col-xs-4 = link_to p.crop, p.crop in = succeed "'s" do @@ -12,4 +12,4 @@ %br/ %small %i - = p.owner.location + = p.location diff --git a/app/views/plantings/show.html.haml b/app/views/plantings/show.html.haml index 88789ed5a..49be10fa5 100644 --- a/app/views/plantings/show.html.haml +++ b/app/views/plantings/show.html.haml @@ -9,9 +9,11 @@ = tag("meta", property: "og:url", content: request.original_url) = tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME']) -%p= render 'plantings/actions', planting: @planting +- content_for :buttonbar do + = render 'plantings/actions', planting: @planting + .row.planting - .col-md-6 + .col-xs-12.col-sm-6 %dl.dl-horizontal.planting-attributes %dt Owner: %dd @@ -26,14 +28,17 @@ %dd = link_to "#{@planting.owner}'s", @planting.owner = link_to @planting.garden, @planting.garden - - unless @planting.owner.location.blank? + - if @planting.owner.location.present? (#{@planting.owner.location}) %dt Quantity: %dd= display_planting_quantity(@planting) - - unless @planting.planted_from.blank? - %dt Planted from: - %dd= display_planted_from(@planting) + %dt Planted from: + %dd + - if @planting.parent_seed + = link_to @planting.parent_seed, seed_path(@planting.parent_seed) + - else + = display_planted_from(@planting) %dt Sun or shade? %dd @@ -64,23 +69,23 @@ %dt Last Harvest: %dd #{@planting.days_to_last_harvest} days after planting + %dt Progress + %dd= render 'plantings/progress', planting: @planting, show_explanation: true - %h2 Progress - %p= render 'plantings/progress', planting: @planting, show_explanation: true - %h2 Harvests - %p= render 'plantings/harvests', planting: @planting - - .col-md-6 + .col-xs-12.col-sm-6 = render partial: "crops/index_card", locals: { crop: @planting.crop } - if @planting.owner.location %p %small View other plantings, members and more near = link_to @planting.owner.location, place_path(@planting.owner.location, anchor: "plantings") -- if @planting.description - %h2 Notes - - :growstuff_markdown - #{ @planting.description != "" ? strip_tags(@planting.description) : "No description given." } - -= render 'photos/item_photos', item: @planting, type: 'planting', photos: @photos +.row + .col-md-6 + - if @planting.description + %h2 Notes + :growstuff_markdown + #{ @planting.description != "" ? strip_tags(@planting.description) : "No description given." } + = render 'plantings/harvests', planting: @planting + = render 'plantings/descendants', planting: @planting + .col-md-6 + = render 'photos/item_photos', item: @planting, type: 'planting', photos: @photos diff --git a/app/views/seeds/_actions.html.haml b/app/views/seeds/_actions.html.haml index 9584182f0..803b63b2d 100644 --- a/app/views/seeds/_actions.html.haml +++ b/app/views/seeds/_actions.html.haml @@ -1,11 +1,15 @@ -- if can? :edit, @seed - = link_to edit_seed_path(@seed), class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-pencil{ title: "Edit" } - Edit - = link_to new_photo_path(id: seed.id, type: 'seed'), class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-camera{ title: "Add photo" } - Add photo -- if can? :destroy, @seed - = link_to @seed, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' do - %span.glyphicon.glyphicon-trash{ title: "Delete" } - Delete + +- if can? :edit, seed + .btn-group + = render 'shared/buttons/edit', path: edit_seed_path(seed) + = render 'shared/buttons/add_photo', path: new_photo_path(id: seed.id, type: 'seed') + + - if can?(:create, Planting) && seed.active? + = link_to new_planting_path(seed_id: seed), class: 'btn btn-default btn-xs' do + %span.glyphicon.glyphicon-grain{ title: "Plant seeds" } + Plant seeds + + = render 'shared/buttons/finish_seeds', seed: seed + +- if can? :destroy, seed + = render 'shared/buttons/delete', path: seed diff --git a/app/views/seeds/_card.html.haml b/app/views/seeds/_card.html.haml new file mode 100644 index 000000000..532db8d6c --- /dev/null +++ b/app/views/seeds/_card.html.haml @@ -0,0 +1,32 @@ +.panel.panel-success + .panel-heading + %h3.panel-title + = link_to seed, seed + - if can? :edit, seed + %a.pull-right{ href: edit_seed_path(seed), role: "button", id: "edit_seed_glyphicon" } + %span.glyphicon.glyphicon-pencil{ title: "Edit" } + .panel-body + .row + .col-md-4 + = link_to image_tag((seed.crop.default_photo ? seed.crop.default_photo.thumbnail_url : 'placeholder_150.png'), + alt: seed.crop.name, class: 'img'), + seed.crop + .col-md-8 + %dl.dl-horizontal + %dt Crop : + %dd= link_to seed.crop.name, seed.crop + - if seed.parent_planting.present? + %dt Saved from + %dd= link_to seed.parent_planting, planting_path(seed.parent_planting) + %dt Plant before : + %dd= seed.plant_before + %dt Quantity : + %dd= seed.quantity + %dt Will trade to : + %dd= seed.tradable_to + %dt From location : + %dd= seed.owner.location + %dt Owner : + %dd= link_to seed.owner.login_name, seed.owner + .col-md-12 + %p= render 'seeds/actions', seed: seed diff --git a/app/views/seeds/_descendants.html.haml b/app/views/seeds/_descendants.html.haml new file mode 100644 index 000000000..1736d0bca --- /dev/null +++ b/app/views/seeds/_descendants.html.haml @@ -0,0 +1,13 @@ +%h2 Plants grown from these seeds +- if @seed.child_plantings + .row + - seed.child_plantings.each do |planting| + .col-md-3 + = render 'plantings/thumbnail', planting: planting +- else + %p No plants grown yet. + +- if can?(:create, Planting) && can?(:edit, seed) + = link_to new_seed_planting_path(seed), class: 'btn btn-primary' do + %span.glyphicon.glyphicon-grain{ title: "Plant seeds" } + Plant seeds diff --git a/app/views/seeds/_form.html.haml b/app/views/seeds/_form.html.haml index b7cb3ea36..9bd2dd280 100644 --- a/app/views/seeds/_form.html.haml +++ b/app/views/seeds/_form.html.haml @@ -9,14 +9,17 @@ %ul - @seed.errors.full_messages.each do |msg| %li= msg - .form-group.required = f.label :crop, 'Crop:', class: 'control-label col-md-2' .col-md-8 - = auto_suggest @seed, :crop, class: 'form-control', default: @crop - %span.help-inline - Can't find what you're looking for? - = link_to "Request new crops.", new_crop_path + - if @planting + = link_to @planting, planting_path(@planting) + = f.hidden_field :parent_planting_id, value: @planting.id + - else + = auto_suggest @seed, :crop, class: 'form-control', default: @crop + %span.help-inline + Can't find what you're looking for? + = link_to "Request new crops.", new_crop_path .form-group = f.label :quantity, 'Quantity:', class: 'control-label col-md-2' .col-md-2 @@ -28,6 +31,19 @@ = f.text_field :plant_before, class: 'add-datepicker form-control', value: @seed.plant_before ? @seed.plant_before.to_s(:ymd) : '' = render partial: 'shared/form_optional' + .form-group + = f.label :finished, 'Mark as finished', class: 'control-label col-md-2' + .col-md-8 + = f.check_box :finished + = render partial: 'shared/form_optional' + %span.help-block + = t('.finish_helper') + .form-group + = f.label :finished_at, 'Finished at:', class: 'control-label col-md-2' + .col-md-2 + = f.text_field :finished_at, class: 'add-datepicker form-control', + value: @seed.finished_at ? @seed.finished_at.to_s(:ymd) : '' + = render partial: 'shared/form_optional' .form-group = f.label :days_until_maturity_min, 'Days until maturity:', class: 'control-label col-md-2' %fieldset diff --git a/app/views/seeds/_thumbnail.html.haml b/app/views/seeds/_thumbnail.html.haml index edd464e57..f985b4d16 100644 --- a/app/views/seeds/_thumbnail.html.haml +++ b/app/views/seeds/_thumbnail.html.haml @@ -1,31 +1,14 @@ -.panel.panel-success - .panel-heading - %h3.panel-title - = link_to "#{seed.owner.login_name}'s seed", seed - - if can? :edit, seed - %a.pull-right{ href: edit_seed_path(seed), role: "button", id: "edit_seed_glyphicon" } - %span.glyphicon.glyphicon-pencil{ title: "Edit" } - .panel-body - .row - .col-md-4 - = link_to image_tag((seed.crop.default_photo ? seed.crop.default_photo.thumbnail_url : 'placeholder_150.png'), - alt: seed.crop.name, class: 'img'), - seed.crop - .col-md-8 - %dl.dl-horizontal - %dt Crop : - %dd= link_to seed.crop.name, seed.crop - %dt Plant before : - %dd= seed.plant_before - %dt Quantity : - %dd= seed.quantity - %dt Will trade to : - %dd= seed.tradable_to - %dt From location : - %dd= seed.owner.location - %dt Owner : - %dd= link_to seed.owner.login_name, seed.owner - .panel-footer - %dt Description - %dd - = display_seed_description(seed) +.thumbnail + .seed-thumbnail + = link_to image_tag((seed.default_photo ? seed.default_photo.thumbnail_url : 'placeholder_150.png'), + alt: seed.crop.name, class: 'img'), + seed_path(seed) + .seedinfo + .seed-name + = link_to seed, seed_path(seed) + .trade-to + %p= seed.owner.location + %p + Will trade to: + %br/ + = seed.tradable_to diff --git a/app/views/seeds/index.html.haml b/app/views/seeds/index.html.haml index 3108bfc56..e7e1ec3e3 100644 --- a/app/views/seeds/index.html.haml +++ b/app/views/seeds/index.html.haml @@ -28,7 +28,7 @@ - unless @seeds.empty? - @seeds.each do |seed| .col-md-6 - = render partial: 'seeds/thumbnail', locals: { seed: seed } + = render 'seeds/card', seed: seed .pagination = page_entries_info @seeds diff --git a/app/views/seeds/show.html.haml b/app/views/seeds/show.html.haml index e15ffb46d..681a21324 100644 --- a/app/views/seeds/show.html.haml +++ b/app/views/seeds/show.html.haml @@ -9,47 +9,56 @@ = tag("meta", property: "og:url", content: request.original_url) = tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME']) +- content_for :buttonbar do + = render 'seeds/actions', seed: @seed + .row .col-md-6 - %p - %b Owner: - = link_to @seed.owner, @seed.owner - — - = link_to "view all #{@seed.owner}'s seeds", seeds_by_owner_path(owner: @seed.owner.slug) - %p - %b Quantity: - = @seed.quantity.blank? ? "not specified" : @seed.quantity - %p - %b Plant before: - = @seed.plant_before.to_s - %p - %b Days until maturity: - = render partial: 'days_until_maturity', locals: { seed: @seed } - %p - %b Organic? - = @seed.organic - %p - %b GMO? - = @seed.gmo - %p - %b Heirloom? - = @seed.heirloom - %p - %b Will trade: - = @seed.tradable_to - - if @seed.owner.location.blank? - (from unspecified location) - - if current_member == @seed.owner - = link_to "Set Location", edit_registration_path(current_member), class: 'btn btn-default btn-xs' - - else - (from - = succeed ")" do - = link_to @seed.owner.location, place_path(@seed.owner.location, anchor: "seeds") + %dl.dl-horizontal + %dt Owner + %dd + = link_to @seed.owner, @seed.owner + — + = link_to "view all #{@seed.owner}'s seeds", + seeds_by_owner_path(owner: @seed.owner.slug) + %dt Quantity: + %dd= @seed.quantity.blank? ? "not specified" : @seed.quantity + %dt Plant before: + %dd= @seed.plant_before.to_s + -if @seed.finished_at + %dt Finished at: + %dd= @seed.finished_at.to_s + %dt Days until maturity: + %dd= render partial: 'days_until_maturity', locals: { seed: @seed } + %dt Organic? + %dd= @seed.organic + %dt GMO? + %dd= @seed.gmo + %dt Heirloom? + %dd= @seed.heirloom + %dt Will trade: + %dd + = @seed.tradable_to + - if @seed.owner.location.blank? + (from unspecified location) + - if current_member == @seed.owner + = link_to "Set Location", edit_registration_path(current_member), class: 'btn btn-default btn-xs' + - else + (from + = succeed ")" do + = link_to @seed.owner.location, place_path(@seed.owner.location, anchor: "seeds") - %p - %b Description: - :growstuff_markdown - #{ @seed.description != "" ? strip_tags(@seed.description) : "No description given." } + %dt When? + %dd + = @seed.created_at + - if @seed.parent_planting + %dt Saved from planting: + %dd + = link_to @seed.parent_planting, planting_path(@seed.parent_planting) + %dt Description: + %dd + :growstuff_markdown + #{ @seed.description != "" ? strip_tags(@seed.description) : "No description given." } - if current_member - if @seed.tradable? && current_member != @seed.owner @@ -60,9 +69,9 @@ - else = render 'shared/signin_signup', to: 'request seeds' - - if can?(:edit, @seed) || can?(:destroy, @seed) - %p - = render 'actions', seed: @seed + = render 'seeds/descendants', seed: @seed + = render 'photos/item_photos', item: @seed, type: 'seed', photos: @photos + .col-md-6 = render partial: "crops/index_card", locals: { crop: @seed.crop } - if @seed.owner.location @@ -75,5 +84,3 @@ Or = link_to "purchase seeds via Ebay", crop_ebay_seeds_url(@seed.crop), target: "_blank", rel: "noopener noreferrer" - -= render 'photos/item_photos', item: @seed, type: 'seed', photos: @photos diff --git a/app/views/shared/buttons/_add_photo.haml b/app/views/shared/buttons/_add_photo.haml new file mode 100644 index 000000000..71e97c0e9 --- /dev/null +++ b/app/views/shared/buttons/_add_photo.haml @@ -0,0 +1,4 @@ +- if can?(:create, Photo) + = link_to path, class: 'btn btn-default btn-xs' do + %span.glyphicon.glyphicon-camera{ title: "Add photo" } + Add photo diff --git a/app/views/shared/buttons/_delete.haml b/app/views/shared/buttons/_delete.haml new file mode 100644 index 000000000..b7490837b --- /dev/null +++ b/app/views/shared/buttons/_delete.haml @@ -0,0 +1,4 @@ += link_to path, method: :delete, + data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' do + %span.glyphicon.glyphicon-trash{ title: "Delete" } + Delete diff --git a/app/views/shared/buttons/_edit.haml b/app/views/shared/buttons/_edit.haml new file mode 100644 index 000000000..87d464023 --- /dev/null +++ b/app/views/shared/buttons/_edit.haml @@ -0,0 +1,3 @@ += link_to path, class: 'btn btn-default btn-xs' do + %span.glyphicon.glyphicon-pencil{ title: "Edit" } + Edit diff --git a/app/views/shared/buttons/_finish_planting.html.haml b/app/views/shared/buttons/_finish_planting.html.haml new file mode 100644 index 000000000..9a3b6ce75 --- /dev/null +++ b/app/views/shared/buttons/_finish_planting.html.haml @@ -0,0 +1,5 @@ +- unless planting.finished + = link_to planting_path(planting, planting: { finished: 1 }), + method: :put, class: 'btn btn-default btn-xs append-date' do + %span.glyphicon.glyphicon-ok{ title: "Finished" } + Mark as finished diff --git a/app/views/shared/buttons/_finish_seeds.haml b/app/views/shared/buttons/_finish_seeds.haml new file mode 100644 index 000000000..211e3ec8b --- /dev/null +++ b/app/views/shared/buttons/_finish_seeds.haml @@ -0,0 +1,5 @@ +- unless seed.finished + = link_to seed_path(seed, seed: { finished: 1 }), + method: :put, class: 'btn btn-default btn-xs append-date' do + %span.glyphicon.glyphicon-ok{ title: "Finished" } + Mark as finished diff --git a/app/views/shared/buttons/_harvest_planting.haml b/app/views/shared/buttons/_harvest_planting.haml new file mode 100644 index 000000000..c90e163ad --- /dev/null +++ b/app/views/shared/buttons/_harvest_planting.haml @@ -0,0 +1,4 @@ +- planting.active? && if can?(:create, Harvest) && can?(:edit, planting) + = link_to new_planting_harvest_path(planting), class: 'btn btn-default btn-xs' do + %span.glyphicon.glyphicon-leaf{ title: "Harvest" } + Harvest diff --git a/app/views/shared/buttons/_save_seeds.haml b/app/views/shared/buttons/_save_seeds.haml new file mode 100644 index 000000000..00d5febb0 --- /dev/null +++ b/app/views/shared/buttons/_save_seeds.haml @@ -0,0 +1,4 @@ +- if planting.active? + = link_to new_planting_seed_path(planting), class: 'btn btn-default btn-xs' do + %span.glyphicon.glyphicon-heart{ title: "Save seeds" } + Save seeds diff --git a/config/routes.rb b/config/routes.rb index 777536e38..52517f580 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -23,6 +23,7 @@ Growstuff::Application.routes.draw do resources :plantings do resources :harvests + resources :seeds end get '/plantings/owner/:owner' => 'plantings#index', as: 'plantings_by_owner' get '/plantings/crop/:crop' => 'plantings#index', as: 'plantings_by_crop' @@ -32,7 +33,9 @@ Growstuff::Application.routes.draw do end get '/gardens/owner/:owner' => 'gardens#index', as: 'gardens_by_owner' - resources :seeds + resources :seeds do + resources :plantings + end get '/seeds/owner/:owner' => 'seeds#index', as: 'seeds_by_owner' get '/seeds/crop/:crop' => 'seeds#index', as: 'seeds_by_crop' diff --git a/db/migrate/20180213005731_seed_usage.rb b/db/migrate/20180213005731_seed_usage.rb new file mode 100644 index 000000000..f768451d2 --- /dev/null +++ b/db/migrate/20180213005731_seed_usage.rb @@ -0,0 +1,22 @@ +class SeedUsage < ActiveRecord::Migration + def change + # # seed can be all sown, meaning there is none left + add_column(:seeds, :finished, :boolean, default: false) + add_column(:seeds, :finished_at, :date, default: nil) + + # plantings can be grown from a seed + add_column(:plantings, :parent_seed_id, :integer) + add_foreign_key(:plantings, :seeds, + column: :parent_seed_id, + primary_key: :id, + name: :parent_seed, + on_delete: :nullify) + # seeds can be harvest from planting + add_column(:seeds, :parent_planting_id, :integer) + add_foreign_key(:seeds, :plantings, + column: :parent_planting_id, + primary_key: :id, + name: :parent_planting, + on_delete: :nullify) + end +end diff --git a/db/schema.rb b/db/schema.rb index c38e122e9..7e9cad2e0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180205000612) do +ActiveRecord::Schema.define(version: 20180213005731) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -409,6 +409,7 @@ ActiveRecord::Schema.define(version: 20180205000612) do t.integer "lifespan" t.integer "days_to_first_harvest" t.integer "days_to_last_harvest" + t.integer "parent_seed_id" end add_index "plantings", ["slug"], name: "index_plantings_on_slug", unique: true, using: :btree @@ -459,10 +460,15 @@ ActiveRecord::Schema.define(version: 20180205000612) do t.text "organic", default: "unknown" t.text "gmo", default: "unknown" t.text "heirloom", default: "unknown" + t.boolean "finished", default: false + t.date "finished_at" + t.integer "parent_planting_id" end add_index "seeds", ["slug"], name: "index_seeds_on_slug", unique: true, using: :btree add_foreign_key "harvests", "plantings" add_foreign_key "photographings", "photos" + add_foreign_key "plantings", "seeds", column: "parent_seed_id", name: "parent_seed", on_delete: :nullify + add_foreign_key "seeds", "plantings", column: "parent_planting_id", name: "parent_planting", on_delete: :nullify end diff --git a/spec/controllers/plantings_controller_spec.rb b/spec/controllers/plantings_controller_spec.rb index abe5ea626..c4fe2396f 100644 --- a/spec/controllers/plantings_controller_spec.rb +++ b/spec/controllers/plantings_controller_spec.rb @@ -90,6 +90,14 @@ describe PlantingsController do it { expect(assigns(:planting).planted_at).to eq Time.zone.today } end + context 'with parent seed' do + let(:seed) { FactoryBot.create :seed, owner: member } + before { get :new, seed_id: seed.to_param } + it { expect(assigns(:seed)).to eq(seed) } + end + end + + describe 'POST :create' do describe "sets the owner automatically" do before { post :create, planting: valid_attributes } it { expect(assigns(:planting).owner).to eq subject.current_member } diff --git a/spec/controllers/seeds_controller_spec.rb b/spec/controllers/seeds_controller_spec.rb index c2fd699eb..a803d8688 100644 --- a/spec/controllers/seeds_controller_spec.rb +++ b/spec/controllers/seeds_controller_spec.rb @@ -1,11 +1,28 @@ require 'rails_helper' describe SeedsController do + let(:owner) { FactoryBot.create(:member) } + describe "GET index" do + before { get :index, owner: owner.slug } it "picks up owner from params" do - owner = FactoryBot.create(:member) - get :index, owner: owner.slug assigns(:owner).should eq(owner) end end + + describe 'GET new' do + before { sign_in owner } + + it { expect(response).to be_success } + + context 'no parent planting' do + before { get :new } + end + + context 'with parent planting' do + let(:planting) { FactoryBot.create :planting, owner: owner } + before { get :new, planting_id: planting.to_param } + it { expect(assigns(:planting)).to eq(planting) } + end + end end diff --git a/spec/factories/seeds.rb b/spec/factories/seeds.rb index 41b3d404f..b58193671 100644 --- a/spec/factories/seeds.rb +++ b/spec/factories/seeds.rb @@ -13,9 +13,17 @@ FactoryBot.define do heirloom 'unknown' days_until_maturity_min nil days_until_maturity_max nil + finished_at nil + + factory :finished_seed do + finished true + finished_at { Date.new } + end factory :tradable_seed do tradable_to "locally" + finished false + finished_at nil end factory :untradable_seed do diff --git a/spec/features/gardens/actions_spec.rb b/spec/features/gardens/actions_spec.rb new file mode 100644 index 000000000..7342fe55e --- /dev/null +++ b/spec/features/gardens/actions_spec.rb @@ -0,0 +1,84 @@ +require 'rails_helper' +require 'custom_matchers' + +feature "Gardens" do + context 'logged in' do + let(:member) { FactoryBot.create :member } + background { login_as member } + subject { page } + let(:garden) { member.gardens.first } + + describe '#index' do + shared_examples "has buttons bar at top" do + it "has buttons bar at top" do + within '.layout-actions' do + is_expected.to have_link 'Add a garden' + is_expected.to have_link 'My Gardens' + is_expected.to have_link "Everyone's gardens" + end + end + end + + context 'my gardens' do + before { visit gardens_path(owner: member) } + include_examples "has buttons bar at top" + it "has actions on garden" do + within '.garden-actions' do + is_expected.to have_link 'Plant something' + is_expected.to have_link 'Mark as inactive' + is_expected.to have_link 'Edit' + is_expected.to have_link 'Add photo' + is_expected.to have_link 'Delete' + end + end + end + context 'all gardens' do + before { visit gardens_path } + include_examples "has buttons bar at top" + end + context "other member's garden" do + before { visit gardens_path(owner: FactoryBot.create(:member)) } + include_examples "has buttons bar at top" + it 'does not show actions on other member garden' do + is_expected.not_to have_link 'Plant something' + is_expected.not_to have_link 'Mark as inactive' + end + end + end + + describe '#show' do + end + end + + # background do + # login_as member + # visit new_garden_path + # end + + # it "has the required fields help text" do + # expect(page).to have_content "* denotes a required field" + # end + + # it "displays required and optional fields properly" do + # expect(page).to have_selector ".form-group.required", text: "Name" + # expect(page).to have_optional 'textarea#garden_description' + # expect(page).to have_optional 'input#garden_location' + # expect(page).to have_optional 'input#garden_area' + # end + + # scenario "Create new garden" do + # fill_in "Name", with: "New garden" + # click_button "Save" + # expect(page).to have_content "Garden was successfully created" + # expect(page).to have_content "New garden" + # end + + # scenario "Refuse to create new garden with negative area" do + # visit new_garden_path + # fill_in "Name", with: "Negative Garden" + # fill_in "Area", with: -5 + # click_button "Save" + # expect(page).not_to have_content "Garden was successfully created" + # expect(page).to have_content "Area must be greater than or equal to 0" + # end +end diff --git a/spec/features/gardens_spec.rb b/spec/features/gardens_spec.rb index 0954d35eb..368389719 100644 --- a/spec/features/gardens_spec.rb +++ b/spec/features/gardens_spec.rb @@ -59,7 +59,7 @@ feature "Planting a crop", js: true do end scenario "button on index to edit garden" do - first(".garden-info").click_link("edit_garden_link") + click_link href: edit_garden_path(garden) expect(page).to have_content 'Edit garden' end end @@ -68,7 +68,9 @@ feature "Planting a crop", js: true do visit new_garden_path fill_in "Name", with: "New garden" click_button "Save" - click_link 'edit_garden_link' + within '.garden-actions' do + click_link 'Edit' + end fill_in "Name", with: "Different name" click_button "Save" expect(page).to have_content "Garden was successfully updated" diff --git a/spec/features/harvests/browse_harvests_spec.rb b/spec/features/harvests/browse_harvests_spec.rb index 2a8400c2e..c51be9f41 100644 --- a/spec/features/harvests/browse_harvests_spec.rb +++ b/spec/features/harvests/browse_harvests_spec.rb @@ -4,19 +4,14 @@ feature "browse harvests" do let!(:member) { create :member } let!(:harvest) { create :harvest, owner: member } - background do - login_as member - end - + background { login_as member } + subject { page } feature 'blank optional fields' do let!(:harvest) { create :harvest, :no_description } - - before(:each) do - visit harvests_path - end + before { visit harvests_path } scenario 'read more' do - expect(page).not_to have_link "Read more" + is_expected.not_to have_link "Read more" end end @@ -28,11 +23,11 @@ feature "browse harvests" do end scenario 'read more' do - expect(page).to have_link "Read more" + is_expected.to have_link "Read more" end it 'links to #show' do - expect(page).to have_link harvest.crop.name, href: harvest_path(harvest) + is_expected.to have_link harvest.crop.name, href: harvest_path(harvest) end end end diff --git a/spec/features/harvests/harvesting_a_crop_spec.rb b/spec/features/harvests/harvesting_a_crop_spec.rb index 84c4b5a7f..e99c5e814 100644 --- a/spec/features/harvests/harvesting_a_crop_spec.rb +++ b/spec/features/harvests/harvesting_a_crop_spec.rb @@ -78,7 +78,9 @@ feature "Harvesting a crop", :js, :elasticsearch do scenario "Harvesting from planting page" do planting = create :planting, crop: maize, owner: member, garden: member.gardens.first visit planting_path(planting) - click_link "Harvest" + within ".planting-actions" do + click_link "Harvest" + end select plant_part.name, from: 'harvest[plant_part_id]' click_button "Save" diff --git a/spec/features/home/home_spec.rb b/spec/features/home/home_spec.rb new file mode 100644 index 000000000..4137b5e5a --- /dev/null +++ b/spec/features/home/home_spec.rb @@ -0,0 +1,84 @@ +require 'rails_helper' + +feature "home page" do + let(:member) { FactoryBot.create :member } + # let(:seed_photo) { FactoryBot.create :photo } + let(:photo) { FactoryBot.create :photo } + let(:crop) { FactoryBot.create :crop, created_at: 1.day.ago } + + let(:planting) { FactoryBot.create :planting, owner: member, crop: crop } + let(:seed) { FactoryBot.create :tradable_seed, owner: member, crop: crop } + let(:harvest) { FactoryBot.create :harvest, owner: member, crop: crop } + + let!(:tradable_seed) { FactoryBot.create :tradable_seed, finished: false } + let!(:finished_seed) { FactoryBot.create :tradable_seed, finished: true } + let!(:untradable_seed) { FactoryBot.create :untradable_seed } + background do + # Add photos, so they can appear on home page + planting.photos << photo + seed.photos << photo + harvest.photos << photo + end + + subject { page } + before { visit root_path } + + shared_examples 'shows seeds' do + it "show tradeable seed" do + is_expected.to have_link href: seed_path(tradable_seed) + end + it "does not show finished seeds" do + is_expected.not_to have_link href: seed_path(finished_seed) + end + it "does not show untradable seeds" do + is_expected.not_to have_link href: seed_path(untradable_seed) + end + + it { is_expected.to have_text 'View all seeds' } + end + + shared_examples 'show plantings' do + it 'shows plantings section' do + is_expected.to have_text 'Recently Planted' + is_expected.to have_link href: planting_path(planting) + end + end + shared_examples 'show harvests' do + it 'shows harvests section' do + is_expected.to have_text 'Recently Harvested' + is_expected.to have_link href: harvest_path(harvest) + end + end + + shared_examples "show crops" do + describe 'shows crops section' do + it { is_expected.to have_text 'Some of our crops' } + it { is_expected.to have_link href: crop_path(crop) } + end + describe 'shows recently added crops' do + it { is_expected.to have_text 'Recently Added' } + it 'link to newest crops' do + is_expected.to have_link crop.name, href: crop_path(crop) + end + end + it 'includes a link to all crops' do + is_expected.to have_link 'View all crops' + end + end + + context 'when anonymous' do + include_examples 'show crops' + include_examples 'show plantings' + include_examples 'show harvests' + include_examples 'shows seeds' + it { is_expected.to have_text 'community of food gardeners' } + end + + context "when signed in" do + background { login_as member } + include_examples 'show crops' + include_examples 'show plantings' + include_examples 'show harvests' + include_examples 'shows seeds' + end +end diff --git a/spec/features/photos/new_photo_spec.rb b/spec/features/photos/new_photo_spec.rb index 1c13b2793..ee2a50691 100644 --- a/spec/features/photos/new_photo_spec.rb +++ b/spec/features/photos/new_photo_spec.rb @@ -33,7 +33,9 @@ feature "new photo page" do scenario "add photo" do visit garden_path(garden) - click_link "Add photo" + within '.garden-actions' do + click_link "Add photo" + end expect(page).to have_text garden.name end end diff --git a/spec/features/seeds/misc_seeds_spec.rb b/spec/features/seeds/misc_seeds_spec.rb index 1db053a80..ec1946d2c 100644 --- a/spec/features/seeds/misc_seeds_spec.rb +++ b/spec/features/seeds/misc_seeds_spec.rb @@ -5,9 +5,7 @@ feature "seeds", js: true do let(:member) { create :member } let(:crop) { create :crop } - background do - login_as member - end + background { login_as member } scenario "button on index to edit seed" do seed = create :seed, owner: member diff --git a/spec/models/planting_spec.rb b/spec/models/planting_spec.rb index 60a95c245..6948caa75 100644 --- a/spec/models/planting_spec.rb +++ b/spec/models/planting_spec.rb @@ -426,6 +426,22 @@ describe Planting do expect(Planting.joins(:owner).all).not_to include(planting) end + context 'ancestry' do + let(:parent_seed) { FactoryBot.create :seed } + let(:planting) { FactoryBot.create :planting, parent_seed: parent_seed } + it "planting has a parent seed" do + expect(planting.parent_seed).to eq(parent_seed) + end + it "seed has a child planting" do + expect(parent_seed.child_plantings).to eq [planting] + end + describe 'grandchildren' do + let(:grandchild_seed) { FactoryBot.create :seed, parent_planting: planting } + it { expect(grandchild_seed.parent_planting).to eq planting } + it { expect(grandchild_seed.parent_planting.parent_seed).to eq parent_seed } + end + end + # it 'predicts harvest times' do # crop = FactoryBot.create :crop # 10.times do diff --git a/spec/models/seed_spec.rb b/spec/models/seed_spec.rb index e45d0e240..269cb888f 100644 --- a/spec/models/seed_spec.rb +++ b/spec/models/seed_spec.rb @@ -157,4 +157,38 @@ describe Seed do Seed.has_photos.should include(seed) end end + + context 'ancestry' do + let(:parent_planting) { FactoryBot.create :planting } + let(:seed) { FactoryBot.create :seed, parent_planting: parent_planting } + it "seed has a parent planting" do + expect(seed.parent_planting).to eq(parent_planting) + end + it "planting has a child seed" do + expect(parent_planting.child_seeds).to eq [seed] + end + end + + context "finished" do + describe 'has finished fields' do + let(:seed) { FactoryBot.create(:finished_seed) } + it { expect(seed.finished).to eq true } + it { expect(seed.finished_at).to be_an_instance_of Date } + end + + describe 'scopes' do + let!(:seed) { FactoryBot.create(:seed) } + let!(:finished_seed) { FactoryBot.create(:finished_seed) } + + describe 'has finished scope' do + it { expect(Seed.finished).to include finished_seed } + it { expect(Seed.finished).not_to include seed } + end + + describe 'has current scope' do + it { expect(Seed.current).to include seed } + it { expect(Seed.current).not_to include finished_seed } + end + end + end end diff --git a/spec/views/gardens/show.html.haml_spec.rb b/spec/views/gardens/show.html.haml_spec.rb index 7130e2e4f..5594c6755 100644 --- a/spec/views/gardens/show.html.haml_spec.rb +++ b/spec/views/gardens/show.html.haml_spec.rb @@ -43,7 +43,7 @@ describe "gardens/show" do end it 'should have an edit button' do - rendered.should have_link 'edit_garden_link' + rendered.should have_link 'Edit' end it "shows a 'plant something' button" do diff --git a/spec/views/home/_crops.html.haml_spec.rb b/spec/views/home/_crops.html.haml_spec.rb deleted file mode 100644 index 3ed655438..000000000 --- a/spec/views/home/_crops.html.haml_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'rails_helper' - -describe 'home/_crops.html.haml', type: "view" do - let!(:crop) { FactoryBot.create(:crop, plantings: FactoryBot.create_list(:planting, 3)) } - let!(:photo) { FactoryBot.create(:photo, plantings: [crop.plantings.first]) } - let(:planting) { crop.plantings.first } - - before(:each) { render } - it 'shows crops section' do - assert_select 'h2', text: 'Some of our crops' - assert_select "a[href='#{crop_path(crop)}']" - end - - it 'shows plantings section' do - assert_select 'h2', text: 'Recently planted' - rendered.should have_content planting.location - end - - it 'shows recently added crops' do - assert_select 'h2', text: 'Recently planted' - end - - it 'includes a link to all crops' do - assert_select "a[href='#{crops_path}']", text: /View all crops/ - end -end diff --git a/spec/views/plantings/show.html.haml_spec.rb b/spec/views/plantings/show.html.haml_spec.rb index 899724ac7..47a742c58 100644 --- a/spec/views/plantings/show.html.haml_spec.rb +++ b/spec/views/plantings/show.html.haml_spec.rb @@ -35,11 +35,10 @@ describe "plantings/show" do rendered.should have_content 'cutting' end - it "doesn't show planted_from if blank" do + it "shows planted_from if blank" do planting.update(planted_from: '') render - rendered.should_not have_content 'Planted from:' - rendered.should_not have_content 'cutting' + rendered.should have_content 'Planted from: not specified' end end