From b7321ed46f636be317ce89835c009ff308007e37 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Fri, 20 Sep 2019 22:07:14 +1200 Subject: [PATCH 01/27] Add source to photos --- app/assets/stylesheets/_crops.scss | 31 +++++++++++++++++ app/controllers/photos_controller.rb | 33 +++++++------------ app/models/photo.rb | 6 +++- app/views/crops/_tiny.html.haml | 6 ++++ app/views/photos/_card.html.haml | 2 +- app/views/photos/new.html.haml | 9 ++--- app/views/photos/show.html.haml | 32 +++++++++--------- db/migrate/20190910022329_add_photo_source.rb | 7 ++++ spec/controllers/photos_controller_spec.rb | 25 +++++++------- spec/factories/photos.rb | 3 +- 10 files changed, 95 insertions(+), 59 deletions(-) create mode 100644 app/views/crops/_tiny.html.haml create mode 100644 db/migrate/20190910022329_add_photo_source.rb diff --git a/app/assets/stylesheets/_crops.scss b/app/assets/stylesheets/_crops.scss index 8c05b9652..d56530bb5 100644 --- a/app/assets/stylesheets/_crops.scss +++ b/app/assets/stylesheets/_crops.scss @@ -1,3 +1,7 @@ +.crop-icon { + height: 1em; +} + .planting { .crop-card { height: 100%; @@ -30,3 +34,30 @@ .remove-altname-row { display: none; } + +.crop-chip { + background-color: lighten($green, 20%); + border-radius: 25px; + display: inline-block; + font-size: 1em; + height: 30px; + line-height: 30px; + margin: .2em; + padding: 0 25px; + + a { + color: $white; + } + + img { + border-radius: 50%; + float: left; + height: 30px; + margin: 0 10px 0 -25px; + width: 30px; + } +} + +.crop-hero-photo { + max-height: 300px; +} diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index fe3f84d02..c8908801e 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -29,8 +29,8 @@ class PhotosController < ApplicationController def new @photo = Photo.new @item = item_to_link_to - @type = item_type - @id = item_id + @type = params[:type] + @id = params[:id] retrieve_from_flickr respond_with @photo end @@ -63,31 +63,17 @@ class PhotosController < ApplicationController private - # - # Params - def item_id - params[:id] - end - - def item_type - params[:type] - end - - def flickr_photo_id_param - params[:photo][:flickr_photo_id] - end - def photo_params - params.require(:photo).permit(:flickr_photo_id, :title, :license_name, + params.require(:photo).permit(:source_id, :source, :title, :license_name, :license_url, :thumbnail_url, :fullsize_url, :link_url) end # Item with photos attached def item_to_link_to - raise "No item id provided" if item_id.nil? - raise "No item type provided" if item_type.nil? + raise "No item id provided" if params[:id].nil? + raise "No item type provided" if params[:type].nil? - item_class = item_type.capitalize + item_class = params[:type].capitalize raise "Photos not supported" unless Photo::PHOTO_CAPABLE.include? item_class item_class.constantize.find(params[:id]) @@ -96,8 +82,11 @@ class PhotosController < ApplicationController # # Flickr retrieval def find_or_create_photo_from_flickr_photo - photo = Photo.find_by(flickr_photo_id: flickr_photo_id_param) - photo ||= Photo.new(photo_params) + photo = Photo.find_or_initialize_by( + source_id: photo_params[:source_id], + source: 'flickr' + ) + photo.update(photo_params) photo.owner_id = current_member.id photo.set_flickr_metadata! photo diff --git a/app/models/photo.rb b/app/models/photo.rb index 8ed9c2f57..a2f80e858 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -24,7 +24,7 @@ class Photo < ApplicationRecord # for easier stubbing and testing. def flickr_metadata flickr = owner.flickr - info = flickr.photos.getInfo(photo_id: flickr_photo_id) + info = flickr.photos.getInfo(photo_id: source_id) licenses = flickr.photos.licenses.getInfo license = licenses.find { |l| l.id == info.license } { @@ -63,4 +63,8 @@ class Photo < ApplicationRecord def to_s "#{title} by #{owner.login_name}" end + + def flickr_photo_id + source_id if source == 'flickr' + end end diff --git a/app/views/crops/_tiny.html.haml b/app/views/crops/_tiny.html.haml new file mode 100644 index 000000000..4e18c5871 --- /dev/null +++ b/app/views/crops/_tiny.html.haml @@ -0,0 +1,6 @@ +- if crop.approved? || can?(:wrangle, Crop) + .crop-chip + = link_to crop do + = crop.name + - unless crop.approved? + %badge.badge-warning= crop.approval_status diff --git a/app/views/photos/_card.html.haml b/app/views/photos/_card.html.haml index 0d17281f5..d16324610 100644 --- a/app/views/photos/_card.html.haml +++ b/app/views/photos/_card.html.haml @@ -1,5 +1,5 @@ .card.photo-card{id: "photo-#{photo.id}"} - = link_to image_tag(photo.fullsize_url, alt: photo.title, class: 'img img-card'), photo + = link_to image_tag(photo.source == 'flickr' ? photo.fullsize_url : photo.thumbnail_url, alt: photo.title, class: 'img img-card'), photo .card-body %h5.ellipsis= link_to photo.title, photo %i by #{link_to photo.owner, photo.owner} diff --git a/app/views/photos/new.html.haml b/app/views/photos/new.html.haml index 9daefaac3..e60e4fd78 100644 --- a/app/views/photos/new.html.haml +++ b/app/views/photos/new.html.haml @@ -30,12 +30,9 @@ - @photos.each do |photo| .col-md-2.col-6 .card - = link_to image_tag(FlickRaw.url_z(photo), alt: '', class: 'img img-card', - width: 150, height: 150), - photos_path(photo: { flickr_photo_id: photo.id }, type: @type, id: @id), - method: :post - .card-body - %p.photo-title= photo.title + = link_to photos_path(photo: { source_id: photo.id, source: 'flickr' }, id: @id, type: @type ), method: :post do + = image_tag(FlickRaw.url_z(photo), alt: photo.title, class: 'img img-card') + .card-body= photo.title .row.pagination .col-md-12= will_paginate @photos diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index ea309fe42..091cff657 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -12,27 +12,28 @@ %li.breadcrumb-item.active= link_to @photo, @photo .row{id: "photo-#{@photo.id}"} - .col-md-8 - %h1.text-center.ellipsis=@photo.title + .col-md-9 + %h1.text-center.ellipsis + = photo_icon + = @photo.title %p.text-center - = image_tag(@photo.fullsize_url, alt: @photo.title, class: 'rounded img-fluid shadow-sm') - .col-md-4 - + = image_tag(@photo.fullsize_url, alt: @photo.title, class: 'rounded img-responsive shadow-sm') + .col-md-3 %p = render 'photos/actions', photo: @photo - = link_to "View on Flickr", @photo.link_url, class: 'btn' + = link_to @photo.link_url, class: 'btn btn-info' do + - if @photo.source == 'flickr' + = icon 'fab', 'flickr' + View on #{@photo.source} %span.btn= render 'photos/likes', photo: @photo - - if @crops.size.positive? - .index-cards - - @crops.each do |crop| - = render 'crops/thumbnail', crop: crop + - @crops.each do |crop| + = render 'crops/tiny', crop: crop %p - = photo_icon - %strong Photo by - = link_to @photo.owner, @photo.owner - Taken on #{@photo.date_taken} + = render 'members/tiny', member: @photo.owner + - if @photo.date_taken.present? + Taken on #{I18n.l @photo.date_taken.to_date} %p %strong License: - if @photo.license_url @@ -40,5 +41,4 @@ - else = @photo.license_name - - if @photo.associations? - = render "associations", photo: @photo \ No newline at end of file + = render "associations", photo: @photo \ No newline at end of file diff --git a/db/migrate/20190910022329_add_photo_source.rb b/db/migrate/20190910022329_add_photo_source.rb new file mode 100644 index 000000000..461329cc8 --- /dev/null +++ b/db/migrate/20190910022329_add_photo_source.rb @@ -0,0 +1,7 @@ +class AddPhotoSource < ActiveRecord::Migration[5.2] + def change + add_column :photos, :source, :string + rename_column :photos, :flickr_photo_id, :source_id + Photo.update_all(source: 'flickr') + end +end diff --git a/spec/controllers/photos_controller_spec.rb b/spec/controllers/photos_controller_spec.rb index c2848f528..d856939cc 100644 --- a/spec/controllers/photos_controller_spec.rb +++ b/spec/controllers/photos_controller_spec.rb @@ -90,7 +90,7 @@ describe PhotosController do it "attaches the photo to a planting" do post :create, params: { - photo: { flickr_photo_id: photo.flickr_photo_id }, + photo: { source_id: photo.source_id, source: 'flickr' }, type: "planting", id: planting.id } expect(flash[:alert]).not_to be_present @@ -100,10 +100,10 @@ describe PhotosController do describe "doesn't attach a photo to a planting twice" do before do post :create, params: { - photo: { flickr_photo_id: photo.flickr_photo_id }, type: "planting", id: planting.id + photo: { source_id: photo.source_id, source: 'flickr' }, type: "planting", id: planting.id } post :create, params: { - photo: { flickr_photo_id: photo.flickr_photo_id }, type: "planting", id: planting.id + photo: { source_id: photo.source_id, source: 'flickr' }, type: "planting", id: planting.id } end @@ -112,17 +112,17 @@ describe PhotosController do end it "attaches the photo to a harvest" do - post :create, params: { photo: { flickr_photo_id: photo.flickr_photo_id }, type: "harvest", id: harvest.id } + post :create, params: { photo: { source_id: photo.source_id, source: 'flickr' }, type: "harvest", id: harvest.id } expect(flash[:alert]).not_to be_present Photo.last.harvests.first.should eq harvest end it "doesn't attach a photo to a harvest twice" do post :create, params: { - photo: { flickr_photo_id: photo.flickr_photo_id }, type: "harvest", id: harvest.id + photo: { source_id: photo.source_id, source: 'flickr' }, type: "harvest", id: harvest.id } post :create, params: { - photo: { flickr_photo_id: photo.flickr_photo_id }, type: "harvest", id: harvest.id + photo: { source_id: photo.source_id, source: 'flickr' }, type: "harvest", id: harvest.id } expect(flash[:alert]).not_to be_present Photo.last.harvests.size.should eq 1 @@ -132,7 +132,7 @@ describe PhotosController do comment = FactoryBot.create(:comment) expect do post :create, params: { - photo: { flickr_photo_id: photo.flickr_photo_id }, type: "comment", id: comment.id + photo: { source_id: photo.source_id, source: 'flickr' }, type: "comment", id: comment.id } end.to raise_error end @@ -140,7 +140,7 @@ describe PhotosController do describe "for the second time" do let(:planting) { FactoryBot.create :planting, owner: member } - let(:valid_params) { { photo: { flickr_photo_id: 1 }, id: planting.id, type: 'planting' } } + let(:valid_params) { { photo: { source_id: 1 }, id: planting.id, type: 'planting' } } it "does not add a photo twice" do expect { post :create, params: valid_params }.to change(Photo, :count).by(1) @@ -154,14 +154,14 @@ describe PhotosController do it "creates the planting/photo link" do planting = FactoryBot.create(:planting, garden: garden, owner: member) photo = FactoryBot.create(:photo, owner: member) - post :create, params: { photo: { flickr_photo_id: photo.flickr_photo_id }, type: "planting", id: planting.id } + post :create, params: { photo: { source_id: photo.source_id, source: 'flickr' }, type: "planting", id: planting.id } expect(flash[:alert]).not_to be_present expect(Photo.last.plantings.first).to eq planting end describe "creates the harvest/photo link" do before do - post :create, params: { photo: { flickr_photo_id: photo.flickr_photo_id }, type: "harvest", id: harvest.id } + post :create, params: { photo: { source_id: photo.source_id, source: 'flickr' }, type: "harvest", id: harvest.id } end it { expect(flash[:alert]).not_to be_present } @@ -177,7 +177,8 @@ describe PhotosController do another_planting = FactoryBot.create(:planting) expect do post :create, params: { - photo: { flickr_photo_id: photo.flickr_photo_id }, type: "planting", id: another_planting.id + photo: { source_id: photo.source_id, source: 'flickr' }, + type: "planting", id: another_planting.id } end.to raise_error(ActiveRecord::RecordInvalid) Photo.last.plantings.first.should_not eq another_planting @@ -188,7 +189,7 @@ describe PhotosController do another_harvest = FactoryBot.create(:harvest) expect do post :create, params: { - photo: { flickr_photo_id: photo.flickr_photo_id }, type: "harvest", id: another_harvest.id + photo: { source_id: photo.source_id, source: 'flickr' }, type: "harvest", id: another_harvest.id } end.to raise_error(ActiveRecord::RecordInvalid) Photo.last.harvests.first.should_not eq another_harvest diff --git a/spec/factories/photos.rb b/spec/factories/photos.rb index b0a64331e..98625bde7 100644 --- a/spec/factories/photos.rb +++ b/spec/factories/photos.rb @@ -3,7 +3,8 @@ FactoryBot.define do factory :photo do owner - flickr_photo_id { 1 } + source { 'flickr' } + source_id { 1 } title { Faker::Movies::HarryPotter.quote } license_name { "CC-BY" } license_url { "http://example.com/license.html" } From 367377088b7b8ac81bac3f737f3cc9e9e15fc8a6 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 21 Sep 2019 09:37:55 +1200 Subject: [PATCH 02/27] Fix specs for photo sources --- app/views/photos/show.html.haml | 2 +- spec/views/photos/show.html.haml_spec.rb | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index 091cff657..67f2da1a6 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -24,7 +24,7 @@ = link_to @photo.link_url, class: 'btn btn-info' do - if @photo.source == 'flickr' = icon 'fab', 'flickr' - View on #{@photo.source} + View on #{@photo.source.titleize} %span.btn= render 'photos/likes', photo: @photo - if @crops.size.positive? diff --git a/spec/views/photos/show.html.haml_spec.rb b/spec/views/photos/show.html.haml_spec.rb index a4a275751..f0f1235ef 100644 --- a/spec/views/photos/show.html.haml_spec.rb +++ b/spec/views/photos/show.html.haml_spec.rb @@ -21,22 +21,25 @@ describe "photos/show" do end it "links to the owner's profile" do - assert_select "a", href: @photo.owner + expect(rendered).to have_link(href: member_path(@photo.owner)) end it "shows a link to the original image" do - assert_select "a", href: @photo.link_url, text: "View on Flickr" + expect(rendered).to have_link 'View on Flickr', href: @photo.link_url end it "links to harvest" do assert_select "a", href: harvest_path(harvest) end + it "links to planting" do assert_select "a", href: planting_path(planting) end + it "links to garden" do assert_select "a", href: garden_path(garden) end + it "links to seeds" do assert_select "a", href: seed_path(seed) end From 60ceef4fceb28201c14e1724f16cce2144943622 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 21 Sep 2019 09:43:36 +1200 Subject: [PATCH 03/27] Only show photo associations if we have any --- app/views/photos/_associations.html.haml | 57 ++++++++++++------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/app/views/photos/_associations.html.haml b/app/views/photos/_associations.html.haml index 5e05c27e2..a6329848b 100644 --- a/app/views/photos/_associations.html.haml +++ b/app/views/photos/_associations.html.haml @@ -1,31 +1,32 @@ -%h4 This photo depicts: -%p - %ul.associations - - @photo.posts.each do |post| - %li - = post_icon - = link_to post.subject, post - = render "association_delete_button", photo: @photo, type: 'post', thing: post - - @photo.plantings.each do |planting| - %li - = planting_icon - = link_to t('photos.show.planting', planting: planting.to_s, owner: planting.owner.to_s), planting_path(planting) - = render "association_delete_button", photo: @photo, type: 'planting', thing: planting +- if @photo.associations.any? + %h4 This photo depicts: + %p + %ul.associations + - @photo.posts.each do |post| + %li + = post_icon + = link_to post.subject, post + = render "association_delete_button", photo: @photo, type: 'post', thing: post + - @photo.plantings.each do |planting| + %li + = planting_icon + = link_to t('photos.show.planting', planting: planting.to_s, owner: planting.owner.to_s), planting_path(planting) + = render "association_delete_button", photo: @photo, type: 'planting', thing: planting - - @photo.harvests.each do |harvest| - %li - = harvest_icon - = link_to t('photos.show.harvest', crop: harvest.crop.name, owner: harvest.owner.to_s), harvest_path(harvest) - = render "association_delete_button", photo: @photo, type: 'harvest', thing: harvest + - @photo.harvests.each do |harvest| + %li + = harvest_icon + = link_to t('photos.show.harvest', crop: harvest.crop.name, owner: harvest.owner.to_s), harvest_path(harvest) + = render "association_delete_button", photo: @photo, type: 'harvest', thing: harvest - - @photo.gardens.each do |garden| - %li - = garden_icon - = link_to t('photos.show.garden', garden: garden.to_s, owner: garden.owner.to_s), garden_path(garden) - = render "association_delete_button", photo: @photo, type: 'garden', thing: garden + - @photo.gardens.each do |garden| + %li + = garden_icon + = link_to t('photos.show.garden', garden: garden.to_s, owner: garden.owner.to_s), garden_path(garden) + = render "association_delete_button", photo: @photo, type: 'garden', thing: garden - - @photo.seeds.each do |seed| - %li - = seed_icon - = link_to t('photos.show.seed', seed: seed.to_s, owner: seed.owner.to_s), seed_path(seed) - = render "association_delete_button", photo: @photo, type: 'seed', thing: seed + - @photo.seeds.each do |seed| + %li + = seed_icon + = link_to t('photos.show.seed', seed: seed.to_s, owner: seed.owner.to_s), seed_path(seed) + = render "association_delete_button", photo: @photo, type: 'seed', thing: seed From 87e1a7571bcda1ac151ca71f93792fc7f33bdc40 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 21 Sep 2019 09:45:34 +1200 Subject: [PATCH 04/27] Photo source in the schema --- db/schema.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 1ce9e5deb..9c42b7a59 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_07_21_042146) do +ActiveRecord::Schema.define(version: 2019_09_15_065209) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -153,6 +153,11 @@ ActiveRecord::Schema.define(version: 2019_07_21_042146) do t.datetime "updated_at" end + create_table "crop_companions", force: :cascade do |t| + t.integer "crop_a_id", null: false + t.integer "crop_b_id", null: false + end + create_table "crops", id: :serial, force: :cascade do |t| t.string "name", null: false t.string "en_wikipedia_url" @@ -416,9 +421,10 @@ ActiveRecord::Schema.define(version: 2019_07_21_042146) do t.string "license_name", null: false t.string "license_url" t.string "link_url", null: false - t.string "flickr_photo_id" + t.string "source_id" t.datetime "date_taken" t.integer "likes_count", default: 0 + t.string "source" end create_table "photos_plantings", id: false, force: :cascade do |t| From 5fab14dc8a54fd30d779bc5715407753f9ebbb19 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 21 Sep 2019 10:28:52 +1200 Subject: [PATCH 05/27] Fixed associations view --- app/views/photos/_associations.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/photos/_associations.html.haml b/app/views/photos/_associations.html.haml index a6329848b..f036c0851 100644 --- a/app/views/photos/_associations.html.haml +++ b/app/views/photos/_associations.html.haml @@ -1,4 +1,4 @@ -- if @photo.associations.any? +- if @photo.associations? %h4 This photo depicts: %p %ul.associations From 90035e79b8d1eb9c3334c16734ffcd298af4b9f1 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sun, 22 Sep 2019 10:06:53 +1200 Subject: [PATCH 06/27] Crop to post relationship made more rails standard --- app/models/crop.rb | 7 ++----- app/models/crop_post.rb | 4 ++++ app/models/post.rb | 18 ++++++++---------- db/migrate/20190921211652_crop_posts.rb | 5 +++++ db/schema.rb | 16 ++++++++-------- 5 files changed, 27 insertions(+), 23 deletions(-) create mode 100644 app/models/crop_post.rb create mode 100644 db/migrate/20190921211652_crop_posts.rb diff --git a/app/models/crop.rb b/app/models/crop.rb index e0166744d..b639ed9d7 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -3,10 +3,6 @@ class Crop < ApplicationRecord include PhotoCapable friendly_id :name, use: %i(slugged finders) - ## - ## Triggers - before_destroy { |crop| crop.posts.clear } - ## ## Relationships has_many :scientific_names, dependent: :destroy @@ -22,7 +18,8 @@ class Crop < ApplicationRecord belongs_to :requester, class_name: 'Member', optional: true, inverse_of: :requested_crops belongs_to :parent, class_name: 'Crop', optional: true, inverse_of: :varieties has_many :varieties, class_name: 'Crop', foreign_key: 'parent_id', dependent: :nullify, inverse_of: :parent - has_and_belongs_to_many :posts # rubocop:disable Rails/HasAndBelongsToMany + has_many :crop_posts + has_many :posts, through: :crop_posts, dependent: :delete_all ## ## Scopes diff --git a/app/models/crop_post.rb b/app/models/crop_post.rb new file mode 100644 index 000000000..8aaa15214 --- /dev/null +++ b/app/models/crop_post.rb @@ -0,0 +1,4 @@ +class CropPost < ApplicationRecord + belongs_to :crop + belongs_to :post +end \ No newline at end of file diff --git a/app/models/post.rb b/app/models/post.rb index 685ffee19..c706fb18f 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -9,14 +9,12 @@ class Post < ApplicationRecord belongs_to :author, class_name: 'Member', inverse_of: :posts belongs_to :forum, optional: true has_many :comments, dependent: :destroy - has_and_belongs_to_many :crops # rubocop:disable Rails/HasAndBelongsToMany - # also has_many notifications, but kinda meaningless to get at them - # from this direction, so we won't set up an association for now. + has_many :crop_posts, dependent: :delete_all + has_many :crops, through: :crop_posts # # Triggers - before_destroy { |post| post.crops.clear } - after_save :update_crops_posts_association + after_save :update_crop_posts_association after_create :send_notification default_scope { joins(:author).merge(Member.kept) } # Ensures the owner still exists @@ -59,14 +57,14 @@ class Post < ApplicationRecord private - def update_crops_posts_association - crops.destroy_all + def update_crop_posts_association + crops.clear # look for crops mentioned in the post. eg. [tomato](crop) body.scan(Haml::Filters::GrowstuffMarkdown::CROP_REGEX) do |_m| - # find crop case-insensitively - crop = Crop.case_insensitive_name(Regexp.last_match(1)).first + crop_name = Regexp.last_match(1) + crop = Crop.case_insensitive_name(crop_name).first # create association - crops << crop if crop && !crops.include?(crop) + self.crops << crop if crop && !crops.include?(crop) end end diff --git a/db/migrate/20190921211652_crop_posts.rb b/db/migrate/20190921211652_crop_posts.rb new file mode 100644 index 000000000..c7f2950c5 --- /dev/null +++ b/db/migrate/20190921211652_crop_posts.rb @@ -0,0 +1,5 @@ +class CropPosts < ActiveRecord::Migration[5.2] + def change + rename_table :crops_posts, :crop_posts + end +end diff --git a/db/schema.rb b/db/schema.rb index 1ce9e5deb..eb762a0d0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_07_21_042146) do +ActiveRecord::Schema.define(version: 2019_09_21_211652) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -153,6 +153,13 @@ ActiveRecord::Schema.define(version: 2019_07_21_042146) do t.datetime "updated_at" end + create_table "crop_posts", id: false, force: :cascade do |t| + t.integer "crop_id" + t.integer "post_id" + t.index ["crop_id", "post_id"], name: "index_crop_posts_on_crop_id_and_post_id" + t.index ["crop_id"], name: "index_crop_posts_on_crop_id" + end + create_table "crops", id: :serial, force: :cascade do |t| t.string "name", null: false t.string "en_wikipedia_url" @@ -176,13 +183,6 @@ ActiveRecord::Schema.define(version: 2019_07_21_042146) do t.index ["slug"], name: "index_crops_on_slug", unique: true end - create_table "crops_posts", id: false, force: :cascade do |t| - t.integer "crop_id" - t.integer "post_id" - t.index ["crop_id", "post_id"], name: "index_crops_posts_on_crop_id_and_post_id" - t.index ["crop_id"], name: "index_crops_posts_on_crop_id" - end - create_table "follows", id: :serial, force: :cascade do |t| t.integer "follower_id" t.integer "followed_id" From fab9560c46c945092b539e05d8983f59faddba3e Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sun, 22 Sep 2019 13:22:02 +1200 Subject: [PATCH 07/27] Apply suggestions from code review --- app/models/crop.rb | 2 +- app/models/crop_post.rb | 2 +- app/models/post.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index b639ed9d7..857b8e132 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -18,7 +18,7 @@ class Crop < ApplicationRecord belongs_to :requester, class_name: 'Member', optional: true, inverse_of: :requested_crops belongs_to :parent, class_name: 'Crop', optional: true, inverse_of: :varieties has_many :varieties, class_name: 'Crop', foreign_key: 'parent_id', dependent: :nullify, inverse_of: :parent - has_many :crop_posts + has_many :crop_posts, dependent: :delete_all has_many :posts, through: :crop_posts, dependent: :delete_all ## diff --git a/app/models/crop_post.rb b/app/models/crop_post.rb index 8aaa15214..5c520e3b6 100644 --- a/app/models/crop_post.rb +++ b/app/models/crop_post.rb @@ -1,4 +1,4 @@ class CropPost < ApplicationRecord belongs_to :crop belongs_to :post -end \ No newline at end of file +end diff --git a/app/models/post.rb b/app/models/post.rb index c706fb18f..b2a8b88fd 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -64,7 +64,7 @@ class Post < ApplicationRecord crop_name = Regexp.last_match(1) crop = Crop.case_insensitive_name(crop_name).first # create association - self.crops << crop if crop && !crops.include?(crop) + crops << crop if crop && !crops.include?(crop) end end From 17b468d440eb1d9861ac0da9e4128ac0d3720e6b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2019 09:50:10 +0000 Subject: [PATCH 08/27] Bump factory_bot_rails from 5.0.2 to 5.1.0 Bumps [factory_bot_rails](https://github.com/thoughtbot/factory_bot_rails) from 5.0.2 to 5.1.0. - [Release notes](https://github.com/thoughtbot/factory_bot_rails/releases) - [Changelog](https://github.com/thoughtbot/factory_bot_rails/blob/master/NEWS.md) - [Commits](https://github.com/thoughtbot/factory_bot_rails/compare/v5.0.2...v5.1.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 726ea0691..7029ae895 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -182,10 +182,10 @@ GEM erubis (2.7.0) excon (0.64.0) execjs (2.7.0) - factory_bot (5.0.2) + factory_bot (5.1.0) activesupport (>= 4.2.0) - factory_bot_rails (5.0.2) - factory_bot (~> 5.0.2) + factory_bot_rails (5.1.0) + factory_bot (~> 5.1.0) railties (>= 4.2.0) faker (2.4.0) i18n (~> 1.6.0) From 758db158cb4106d1926509a8ded006351f23b05e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2019 09:35:34 +0000 Subject: [PATCH 09/27] Bump font-awesome-sass from 5.10.2 to 5.11.2 Bumps [font-awesome-sass](https://github.com/FortAwesome/font-awesome-sass) from 5.10.2 to 5.11.2. - [Release notes](https://github.com/FortAwesome/font-awesome-sass/releases) - [Commits](https://github.com/FortAwesome/font-awesome-sass/compare/5.10.2...5.11.2) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7029ae895..c015705df 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -195,7 +195,7 @@ GEM figaro (1.1.1) thor (~> 0.14) flickraw (0.9.10) - font-awesome-sass (5.10.2) + font-awesome-sass (5.11.2) sassc (>= 1.11) friendly_id (5.2.5) activerecord (>= 4.0.0) From bcb2464b531bf7fd4a3631d7ef485b4761558636 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2019 09:34:45 +0000 Subject: [PATCH 10/27] Bump friendly_id from 5.2.5 to 5.3.0 Bumps [friendly_id](https://github.com/norman/friendly_id) from 5.2.5 to 5.3.0. - [Release notes](https://github.com/norman/friendly_id/releases) - [Changelog](https://github.com/norman/friendly_id/blob/master/Changelog.md) - [Commits](https://github.com/norman/friendly_id/compare/5.2.5...5.3.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index c015705df..9b5773e1e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -197,7 +197,7 @@ GEM flickraw (0.9.10) font-awesome-sass (5.11.2) sassc (>= 1.11) - friendly_id (5.2.5) + friendly_id (5.3.0) activerecord (>= 4.0.0) geocoder (1.4.9) gibbon (1.2.1) From 50723532933e4fdc0bee1df35b330f09d1931a79 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Tue, 24 Sep 2019 14:56:40 +1200 Subject: [PATCH 11/27] Only save location (used for post-signin redirect) if this is a format html page --- app/controllers/application_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 023603b33..e30fe25b1 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -15,7 +15,7 @@ class ApplicationController < ActionController::Base "/members/password/edit", "/members/confirmation", "/members/sign_out"]) || request.xhr? - store_location_for(:member, request.fullpath) + store_location_for(:member, request.fullpath) if request.format == :html end end From 8dc56c48e2555e41e5913fcd3af3198424c175b4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2019 10:24:46 +0000 Subject: [PATCH 12/27] Bump scout_apm from 2.6.0 to 2.6.1 Bumps [scout_apm](https://github.com/scoutapp/scout_apm_ruby) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/scoutapp/scout_apm_ruby/releases) - [Changelog](https://github.com/scoutapp/scout_apm_ruby/blob/master/CHANGELOG.markdown) - [Commits](https://github.com/scoutapp/scout_apm_ruby/compare/v2.6.0...v2.6.1) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9b5773e1e..b77a4b5c3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -359,7 +359,7 @@ GEM rack orm_adapter (0.5.0) parallel (1.17.0) - parser (2.6.4.0) + parser (2.6.4.1) ast (~> 2.4.0) percy-capybara (4.0.2) pg (0.21.0) @@ -494,7 +494,7 @@ GEM sprockets (> 3.0) sprockets-rails tilt - scout_apm (2.6.0) + scout_apm (2.6.1) parser searchkick (4.1.0) activemodel (>= 5) From 719fec24d0fd7af2c79c3f3a6d2b69a6e6ea1ecd Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 21 Sep 2019 10:21:12 +1200 Subject: [PATCH 13/27] if someone is destroy, delete all likes --- app/models/concerns/likeable.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/concerns/likeable.rb b/app/models/concerns/likeable.rb index 4937af53e..9db3da6e5 100644 --- a/app/models/concerns/likeable.rb +++ b/app/models/concerns/likeable.rb @@ -2,7 +2,7 @@ module Likeable extend ActiveSupport::Concern included do - has_many :likes, as: :likeable, inverse_of: :likeable, dependent: :destroy + has_many :likes, as: :likeable, inverse_of: :likeable, dependent: :delete_all has_many :members, through: :likes end From 99e2ca492061b982ced103f63e2507d1f007c5a2 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 21 Sep 2019 10:21:37 +1200 Subject: [PATCH 14/27] If a crop is deleted, delete association (gerund) records too --- app/models/crop.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index e0166744d..111756069 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -9,13 +9,13 @@ class Crop < ApplicationRecord ## ## Relationships - has_many :scientific_names, dependent: :destroy + has_many :scientific_names, dependent: :delete_all accepts_nested_attributes_for :scientific_names, allow_destroy: true, reject_if: :all_blank - has_many :alternate_names, dependent: :destroy + has_many :alternate_names, dependent: :delete_all has_many :plantings, dependent: :destroy has_many :seeds, dependent: :destroy has_many :harvests, dependent: :destroy - has_many :photo_associations, dependent: :destroy + has_many :photo_associations, dependent: :delete_all has_many :photos, through: :photo_associations has_many :plant_parts, -> { joins_members.distinct.order("plant_parts.name") }, through: :harvests belongs_to :creator, class_name: 'Member', optional: true, inverse_of: :created_crops From 66a3b2c52b843d9f71daac9b389961cd48cb8feb Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 21 Sep 2019 10:21:54 +1200 Subject: [PATCH 15/27] If we delete a photo, delete the associations records --- app/models/concerns/photo_capable.rb | 2 +- app/models/photo.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/concerns/photo_capable.rb b/app/models/concerns/photo_capable.rb index dfddef42c..9cb440bd7 100644 --- a/app/models/concerns/photo_capable.rb +++ b/app/models/concerns/photo_capable.rb @@ -2,7 +2,7 @@ module PhotoCapable extend ActiveSupport::Concern included do - has_many :photo_associations, as: :photographable, dependent: :destroy, inverse_of: :photographable + has_many :photo_associations, as: :photographable, dependent: :delete_all, inverse_of: :photographable has_many :photos, through: :photo_associations, as: :photographable scope :has_photos, -> { includes(:photos).where.not(photos: { id: nil }) } diff --git a/app/models/photo.rb b/app/models/photo.rb index a2f80e858..304c43c6f 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -4,7 +4,7 @@ class Photo < ApplicationRecord PHOTO_CAPABLE = %w(Garden Planting Harvest Seed Post).freeze - has_many :photo_associations, foreign_key: :photo_id, dependent: :destroy, inverse_of: :photo + has_many :photo_associations, foreign_key: :photo_id, dependent: :delete_all, inverse_of: :photo has_many :crops, through: :photo_associations # creates a relationship for each assignee type From e043199866f9199d1d9075348b0b75d71bf43946 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2019 09:42:34 +0000 Subject: [PATCH 16/27] Bump uglifier from 4.1.20 to 4.2.0 Bumps [uglifier](https://github.com/lautis/uglifier) from 4.1.20 to 4.2.0. - [Release notes](https://github.com/lautis/uglifier/releases) - [Changelog](https://github.com/lautis/uglifier/blob/master/CHANGELOG.md) - [Commits](https://github.com/lautis/uglifier/commits) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index b77a4b5c3..48d41f060 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -535,7 +535,7 @@ GEM trollop (1.16.2) tzinfo (1.2.5) thread_safe (~> 0.1) - uglifier (4.1.20) + uglifier (4.2.0) execjs (>= 0.3.0, < 3) unicode-display_width (1.6.0) unicorn (5.5.1) From 6a4158ae043bc484871f9803532071cbb73622d6 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 28 Sep 2019 10:38:01 +1200 Subject: [PATCH 17/27] =?UTF-8?q?=F0=9F=91=AD=20Crop=20companions=20(#2176?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Crop companions * Use a nil license to mean no licence * dependent for crop->crop_companions relationship * Fix crop detail spec --- app/assets/stylesheets/_predictions.scss | 2 +- app/models/crop.rb | 2 + app/models/crop_companion.rb | 4 + app/views/crops/show.html.haml | 114 ++++++++++-------- .../20190915065209_create_crop_companions.rb | 9 ++ db/schema.rb | 7 ++ spec/factories/crop_companions.rb | 4 + spec/factories/photos.rb | 2 +- spec/features/crops/crop_detail_page_spec.rb | 43 +++---- spec/models/crop_companion_spec.rb | 5 + 10 files changed, 116 insertions(+), 76 deletions(-) create mode 100644 app/models/crop_companion.rb create mode 100644 db/migrate/20190915065209_create_crop_companions.rb create mode 100644 spec/factories/crop_companions.rb create mode 100644 spec/models/crop_companion_spec.rb diff --git a/app/assets/stylesheets/_predictions.scss b/app/assets/stylesheets/_predictions.scss index f16c6ee8f..18d1ac623 100644 --- a/app/assets/stylesheets/_predictions.scss +++ b/app/assets/stylesheets/_predictions.scss @@ -9,7 +9,7 @@ strong { font-align: center; - font-size: 4em; + font-size: 3em; } span { diff --git a/app/models/crop.rb b/app/models/crop.rb index 7dc1ccf01..1c787c8f9 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -18,6 +18,8 @@ class Crop < ApplicationRecord belongs_to :requester, class_name: 'Member', optional: true, inverse_of: :requested_crops belongs_to :parent, class_name: 'Crop', optional: true, inverse_of: :varieties has_many :varieties, class_name: 'Crop', foreign_key: 'parent_id', dependent: :nullify, inverse_of: :parent + has_many :crop_companions, foreign_key: :crop_a_id, inverse_of: :crop_a, dependent: :delete_all + has_many :companions, through: :crop_companions, source: :crop_b, class_name: 'Crop' has_many :crop_posts, dependent: :delete_all has_many :posts, through: :crop_posts, dependent: :delete_all diff --git a/app/models/crop_companion.rb b/app/models/crop_companion.rb new file mode 100644 index 000000000..55d7c27a1 --- /dev/null +++ b/app/models/crop_companion.rb @@ -0,0 +1,4 @@ +class CropCompanion < ApplicationRecord + belongs_to :crop_a, class_name: :Crop + belongs_to :crop_b, class_name: :Crop +end diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index e81ee11b1..131ab483a 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -1,7 +1,6 @@ - content_for :title, @crop.name - content_for :opengraph do - - @crop.photos.each do |photo| - = tag("meta", property: "og:image", content: photo.fullsize_url) + = tag("meta", property: "og:image", content: crop_image_path(@crop)) = tag("meta", property: "og:title", content: @crop.name) = tag("meta", property: "og:type", content: "website") = tag("meta", property: "og:url", content: request.original_url) @@ -12,64 +11,73 @@ - content_for :breadcrumbs do %li.breadcrumb-item= link_to 'Crops', crops_path - %li.breadcrumb-item.active= link_to @crop, @crop - -%h1 - %strong= @crop.name.titleize - %small.text-muted= @crop.default_scientific_name -%p= render 'crops/actions', crop: @crop + %li.breadcrumb-item.active= link_to @crop.name.capitalize, @crop = render 'approval_status_message', crop: @crop +.jumbotron + .row + .col-md-9 + %h1 + %strong= @crop.name.capitalize + - unless @crop.approved? + %badge.badge-warning=@crop.approval_status + %small.text-muted= @crop.default_scientific_name + %p.text-muted + - if !@crop.plantings.empty? + #{@crop.name.capitalize} has been planted + = pluralize(@crop.plantings.size, "time") + by #{ENV['GROWSTUFF_SITE_NAME']} members. + - else + Nobody is growing this yet. You could be the first! + .col-md-3 + = image_tag crop_image_path(@crop), + class: 'img-responsive shadow rounded crop-hero-photo', alt: 'photo of crop' .row .col-md-9 - %p - - if !@crop.plantings.empty? - #{@crop.name.titleize} has been planted - = pluralize(@crop.plantings.size, "time") - by #{ENV['GROWSTUFF_SITE_NAME']} members. - - else - Nobody is growing this yet. You could be the first! - - if @crop.perennial? - #{@crop.name.capitalize} is a perennial crop (living more than two years) - - elsif @crop.annual? - #{@crop.name.capitalize} is an annual crop (living and reproducing in a single year or less) - %hr/ - - = render 'predictions', crop: @crop - %hr/ - = render 'crops/photos', photos: @photos, crop: @crop - - .card-deck.text-center - .col-md-4 - %h3.section-heading.h3.pt-4 Sunniness - = pie_chart crop_sunniness_path(@crop, format: :json), legend: "bottom" - .col-md-4 - %h3.section-heading.h3.pt-4 Planted from - = pie_chart crop_planted_from_path(@crop, format: :json), legend: "bottom" - .col-md-4 - %h3.section-heading.h3.pt-4 Harvested for - = pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom" - - .varieties= render 'varieties', crop: @crop - - %h3 - = icon 'fas', 'map' - Crop Map - %p - Only plantings by members who have set their locations are shown on this map. - - if current_member && current_member.location.blank? - = link_to "Set your location.", edit_member_registration_path - #cropmap.map - - = render 'crops/posts', crop: @crop - + = render 'crops/actions', crop: @crop .col-md-3 = render 'wrangle', crop: @crop + +.row + .col-md-9 + %section.prediction= render 'predictions', crop: @crop + - if @crop.companions.any? + %section.companions + %h2 Companions + - @crop.companions.each do |companion| + = render 'crops/tiny', crop: companion + + %section.photos= render 'crops/photos', photos: @photos, crop: @crop + + - if @crop.plantings.any? + .card-deck.text-center + .col-md-4 + %h3.section-heading.h3.pt-4 Sunniness + = pie_chart crop_sunniness_path(@crop, format: :json), legend: "bottom" + .col-md-4 + %h3.section-heading.h3.pt-4 Planted from + = pie_chart crop_planted_from_path(@crop, format: :json), legend: "bottom" + .col-md-4 + %h3.section-heading.h3.pt-4 Harvested for + = pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom" + + %section.varieties= render 'varieties', crop: @crop + + %section.crop-map + %h2 + = icon 'fas', 'map' + Crop Map + %p + Only plantings by members who have set their locations are shown on this map. + - if current_member && current_member.location.blank? + = link_to "Set your location.", edit_member_registration_path + #cropmap.map + + %section.posts= render 'crops/posts', crop: @crop + + .col-md-3 .card - .crop-image - = image_tag crop_image_path(@crop, full_size: true), - class: 'img-card', alt: 'photo of crop' .card-body %h4 How to grow #{@crop.name.pluralize} = render 'grown_for', crop: @crop @@ -123,7 +131,7 @@ Wikipedia (English) %li.list-group-item - = link_to "https://openfarm.cc/en/crops/#{CGI.escape @crop.name}", + = link_to "https://openfarm.cc/en/crops/#{CGI.escape @crop.name.gsub(' ', '-')}", class: 'card-link', target: "_blank", rel: "noopener noreferrer" do diff --git a/db/migrate/20190915065209_create_crop_companions.rb b/db/migrate/20190915065209_create_crop_companions.rb new file mode 100644 index 000000000..1b9d1b974 --- /dev/null +++ b/db/migrate/20190915065209_create_crop_companions.rb @@ -0,0 +1,9 @@ +class CreateCropCompanions < ActiveRecord::Migration[5.2] + def change + create_table :crop_companions do |t| + t.integer "crop_a_id", null: false + t.integer "crop_b_id", null: false + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index e5726871f..4a450b704 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -153,6 +153,13 @@ ActiveRecord::Schema.define(version: 2019_09_21_211652) do t.datetime "updated_at" end + create_table "crop_companions", force: :cascade do |t| + t.integer "crop_a_id", null: false + t.integer "crop_b_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "crop_posts", id: false, force: :cascade do |t| t.integer "crop_id" t.integer "post_id" diff --git a/spec/factories/crop_companions.rb b/spec/factories/crop_companions.rb new file mode 100644 index 000000000..6db4f0eb0 --- /dev/null +++ b/spec/factories/crop_companions.rb @@ -0,0 +1,4 @@ +FactoryBot.define do + factory :crop_companion do + end +end diff --git a/spec/factories/photos.rb b/spec/factories/photos.rb index 98625bde7..41e581d29 100644 --- a/spec/factories/photos.rb +++ b/spec/factories/photos.rb @@ -14,7 +14,7 @@ FactoryBot.define do factory :unlicensed_photo do license_name { "All rights reserved" } - license_url { "" } + license_url { nil } end end end diff --git a/spec/features/crops/crop_detail_page_spec.rb b/spec/features/crops/crop_detail_page_spec.rb index 3d1449a1d..057226c4a 100644 --- a/spec/features/crops/crop_detail_page_spec.rb +++ b/spec/features/crops/crop_detail_page_spec.rb @@ -61,8 +61,7 @@ describe "crop detail page", js: true do end it "has a link to OpenFarm" do - expect(page).to have_link "OpenFarm - Growing guide", - href: "https://openfarm.cc/en/crops/#{CGI.escape crop.name}" + expect(page).to have_link "OpenFarm - Growing guide" end it "has a link to gardenate" do @@ -123,7 +122,7 @@ describe "crop detail page", js: true do finished_at: 1.day.ago) end - context 'crop is an annual' do + context 'crop is an Annual' do let(:crop) { FactoryBot.create(:annual_crop) } describe 'with no harvests' do @@ -138,14 +137,13 @@ describe "crop detail page", js: true do expect(subject).to have_text "99 days" end - it "describes annual crops" do - expect(subject).to have_text( - "#{crop.name.capitalize} is an annual crop (living and reproducing in a single year or less)" - ) + it "describes Annual crops" do + expect(subject).to have_text("living and reproducing in a single year or less") + expect(subject).to have_text('Annual') end end - context 'crop is perennial' do + context 'crop is Perennial' do let(:crop) { FactoryBot.create :perennial_crop } describe 'with no harvests' do @@ -155,12 +153,13 @@ describe "crop detail page", js: true do include_examples "predicts harvest" end - it "describes perennial crops" do - expect(subject).to have_text("#{crop.name.capitalize} is a perennial crop (living more than two years)") + it "describes Perennial crops" do + expect(subject).to have_text("Perennial") + expect(subject).to have_text("living more than two years") end end - context 'crop perennial value is null' do + context 'crop Perennial value is null' do let(:crop) { FactoryBot.create :crop, perennial: nil } describe 'with no harvests' do @@ -172,28 +171,30 @@ describe "crop detail page", js: true do end end - context 'annual and perennial' do + context 'Annual and Perennial' do before { visit crop_path(crop) } - context 'crop is an annual' do + context 'crop is an Annual' do let(:crop) { FactoryBot.create :annual_crop } - it { expect(page).to have_text 'annual crop (living and reproducing in a single year or less)' } - it { expect(page).not_to have_text 'perennial crop (living more than two years)' } + it { expect(page).to have_text 'Annual' } + it { expect(page).to have_text 'living and reproducing in a single year or less' } + it { expect(page).not_to have_text 'Perennial' } end - context 'crop is perennial' do + context 'crop is Perennial' do let(:crop) { FactoryBot.create :perennial_crop } - it { expect(page).to have_text 'perennial crop (living more than two years)' } - it { expect(page).not_to have_text 'annual crop (living and reproducing in a single year or less)' } + it { expect(page).to have_text 'Perennial' } + it { expect(page).to have_text 'living more than two years' } + it { expect(page).not_to have_text 'Annual' } end - context 'crop perennial value is null' do + context 'crop Perennial value is null' do let(:crop) { FactoryBot.create :crop, perennial: nil } - it { expect(page).not_to have_text 'perennial crop (living more than two years)' } - it { expect(page).not_to have_text 'annual crop (living and reproducing in a single year or less)' } + it { expect(page).not_to have_text 'Perennial' } + it { expect(page).not_to have_text 'Annual' } end end end diff --git a/spec/models/crop_companion_spec.rb b/spec/models/crop_companion_spec.rb new file mode 100644 index 000000000..7b6223db5 --- /dev/null +++ b/spec/models/crop_companion_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe CropCompanion, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From 7b5698f9771bea51cf505114ea503b9e228b918a Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 28 Sep 2019 17:23:25 +1200 Subject: [PATCH 18/27] =?UTF-8?q?=F0=9F=91=A9=E2=80=8D=F0=9F=8C=BE=20Impor?= =?UTF-8?q?t=20openfarm=20data=20(#2177)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Pull in openfarm icons, photos, info * Truncating member location * tidying up harvest display, and reducing duplication in css styles * Tiny crop chip * only show crop charts if there is data to show * Make the styles more Growstuff * Fixed links to openfarm * Updating specs to cope with new photo sources fix broken garden timeline on some pages * Update homepage blurb * Import crop companions * More fluid page * use thumbnail unless the source is flickr * Messing with homepage * Added crop growing_degree_days * expect full size url on photos helper spec * formatted dates from seeds#show * tidy up places#show * Move progress bar * Quicker buttons for approve/reject crops * Remove kaminari gem * use crop cards on hierarchy page * more crops on crops#index * Wrap photo creation in transaction * Wrap crop companions in a transaction --- Gemfile | 9 +- Gemfile.lock | 27 +-- app/assets/stylesheets/_crops.scss | 35 +++ app/assets/stylesheets/_homepage.scss | 91 +------- app/assets/stylesheets/_members.scss | 9 +- app/assets/stylesheets/_photos.scss | 9 - app/assets/stylesheets/_plantings.scss | 39 ---- app/assets/stylesheets/_variables.scss | 18 ++ app/assets/stylesheets/overrides.scss | 220 ++++++++++++------ app/controllers/charts/gardens_controller.rb | 2 +- app/controllers/crops_controller.rb | 32 ++- app/controllers/sessions_controller.rb | 2 +- app/helpers/icons_helper.rb | 10 + app/helpers/photos_helper.rb | 66 +++--- app/models/ability.rb | 1 + app/models/concerns/open_farm_data.rb | 75 ++++++ app/models/crop.rb | 23 +- app/models/photo.rb | 5 +- app/models/photo_association.rb | 8 +- app/services/openfarm_service.rb | 108 +++++++++ app/views/crops/_actions.html.haml | 8 +- app/views/crops/_alternate_names.html.haml | 37 ++- app/views/crops/_crop.html.haml | 2 +- app/views/crops/_form.html.haml | 11 +- app/views/crops/_grown_for.html.haml | 8 +- app/views/crops/_hierarchy.html.haml | 4 +- app/views/crops/_info.haml | 25 ++ app/views/crops/_photos.html.haml | 6 +- app/views/crops/_planting_advice.html.haml | 19 +- app/views/crops/_posts.html.haml | 15 +- app/views/crops/_predictions.html.haml | 81 ++++--- app/views/crops/_scientific_names.html.haml | 30 ++- app/views/crops/_thumbnail.html.haml | 19 +- app/views/crops/_tiny.html.haml | 1 + app/views/crops/_varieties.html.haml | 6 +- app/views/crops/_wrangle.html.haml | 5 +- app/views/crops/index.html.haml | 9 +- app/views/crops/requested.haml | 5 +- app/views/crops/search.html.haml | 43 ++-- app/views/crops/show.html.haml | 5 +- app/views/follows/followers.html.haml | 7 +- app/views/garden_types/index.html.haml | 5 +- app/views/gardens/_actions.html.haml | 2 +- app/views/gardens/_garden.html.haml | 5 + app/views/gardens/index.html.haml | 34 ++- app/views/gardens/show.html.haml | 28 +-- app/views/harvests/_actions.html.haml | 4 +- app/views/harvests/_card.html.haml | 13 +- app/views/harvests/_owner.html.haml | 35 +-- app/views/harvests/_planting.haml | 10 +- app/views/harvests/index.html.haml | 18 +- app/views/harvests/show.html.haml | 60 ++--- app/views/home/_blurb.html.haml | 2 +- app/views/home/_crops.html.haml | 5 +- app/views/home/_harvests.html.haml | 22 +- app/views/home/_members.html.haml | 2 +- app/views/home/_plantings.html.haml | 23 +- app/views/home/_seeds.html.haml | 2 +- app/views/home/index.html.haml | 45 ++-- app/views/layouts/_fact_card.haml | 6 + app/views/layouts/_nav.haml | 17 +- app/views/layouts/_pagination.html.haml | 2 +- app/views/layouts/application.html.haml | 6 +- app/views/members/_location.html.haml | 14 +- app/views/members/_member.haml | 4 +- app/views/members/_tiny.haml | 2 +- app/views/members/nearby.html.haml | 5 +- app/views/members/show.html.haml | 35 +-- app/views/photos/_card.html.haml | 9 +- app/views/photos/_gallery.haml | 2 +- app/views/photos/_hero.html.haml | 7 + app/views/photos/_item_photos.haml | 11 - app/views/photos/_likes.html.haml | 25 +- app/views/photos/_photo.haml | 2 +- app/views/photos/index.html.haml | 22 +- app/views/places/show.html.haml | 42 ++-- app/views/plantings/_actions.html.haml | 4 +- app/views/plantings/_card.html.haml | 8 +- app/views/plantings/_descendants.html.haml | 6 +- app/views/plantings/_facts.haml | 84 +++---- app/views/plantings/_harvests.html.haml | 4 +- app/views/plantings/_owner.haml | 31 +-- app/views/plantings/_progress.html.haml | 4 +- app/views/plantings/_thumbnail.html.haml | 6 +- app/views/plantings/index.html.haml | 31 +-- app/views/plantings/show.html.haml | 32 ++- app/views/posts/_preview.haml | 20 +- app/views/posts/index.html.haml | 66 +++--- app/views/posts/show.html.haml | 15 +- app/views/seeds/_actions.html.haml | 12 +- app/views/seeds/_card.html.haml | 13 +- app/views/seeds/_descendants.html.haml | 16 +- app/views/seeds/_facts.html.haml | 29 +++ app/views/seeds/_owner.html.haml | 19 ++ app/views/seeds/index.html.haml | 25 +- app/views/seeds/show.html.haml | 98 ++++---- app/views/timeline/_photos.html.haml | 5 +- app/views/timeline/index.html.haml | 9 +- config/locales/en.yml | 6 +- config/routes.rb | 1 + ...190902004225_add_openfarm_data_to_crops.rb | 5 + db/migrate/20190918033319_unique_urls.rb | 6 + db/schema.rb | 3 + db/seeds.rb | 2 + lib/tasks/openfarm.rake | 9 + spec/factories/planting.rb | 21 ++ spec/features/crops/request_new_crop_spec.rb | 8 +- spec/features/gardens/actions_spec.rb | 2 +- spec/features/gardens/gardens_spec.rb | 8 +- spec/features/plantings/show_spec.rb | 42 ++++ spec/features/seeds/adding_seeds_spec.rb | 12 +- spec/features/seeds/misc_seeds_spec.rb | 8 +- spec/helpers/photos_helper_spec.rb | 36 +-- .../crops/_planting_advice.html.haml_spec.rb | 67 ------ spec/views/harvests/index.html.haml_spec.rb | 2 +- spec/views/harvests/show.html.haml_spec.rb | 2 +- spec/views/seeds/show.html.haml_spec.rb | 2 +- 117 files changed, 1354 insertions(+), 1086 deletions(-) create mode 100644 app/models/concerns/open_farm_data.rb create mode 100644 app/services/openfarm_service.rb create mode 100644 app/views/crops/_info.haml create mode 100644 app/views/gardens/_garden.html.haml create mode 100644 app/views/layouts/_fact_card.haml create mode 100644 app/views/photos/_hero.html.haml delete mode 100644 app/views/photos/_item_photos.haml create mode 100644 app/views/seeds/_facts.html.haml create mode 100644 app/views/seeds/_owner.html.haml create mode 100644 db/migrate/20190902004225_add_openfarm_data_to_crops.rb create mode 100644 db/migrate/20190918033319_unique_urls.rb create mode 100644 lib/tasks/openfarm.rake create mode 100644 spec/features/plantings/show_spec.rb delete mode 100644 spec/views/crops/_planting_advice.html.haml_spec.rb diff --git a/Gemfile b/Gemfile index cfa8ef248..2672e0aaf 100644 --- a/Gemfile +++ b/Gemfile @@ -54,9 +54,6 @@ gem 'unicorn' # http server gem "comfortable_mexican_sofa", "~> 2.0.0" -gem 'bootstrap-kaminari-views' # bootstrap views for kaminari -gem 'kaminari' # pagination - gem 'active_utils' gem 'sidekiq' @@ -73,6 +70,9 @@ gem 'devise' # nicely formatted URLs gem 'friendly_id' +# validates URLs +gem "validate_url" + # gravatars gem 'gravatar-ultimate' @@ -118,6 +118,9 @@ gem 'rack-protection', '>= 2.0.1' # Member to member messaging system gem 'mailboxer' +gem 'faraday' +gem 'faraday_middleware' + group :production do gem 'bonsai-elasticsearch-rails' # Integration with Bonsa-Elasticsearch on heroku gem 'dalli' diff --git a/Gemfile.lock b/Gemfile.lock index 48d41f060..5dc18108e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -82,10 +82,7 @@ GEM sassc-rails (>= 2.0.0) bootstrap-datepicker-rails (1.8.0.1) railties (>= 3.0) - bootstrap-kaminari-views (0.0.5) - kaminari (>= 0.13) - rails (>= 3.1) - bootstrap_form (4.3.0) + bootstrap_form (4.2.0) actionpack (>= 5.0) activemodel (>= 5.0) builder (3.2.3) @@ -191,6 +188,8 @@ GEM i18n (~> 1.6.0) faraday (0.15.4) multipart-post (>= 1.2, < 3) + faraday_middleware (0.13.1) + faraday (>= 0.7.4, < 1.0) ffi (1.11.1) figaro (1.1.1) thor (~> 0.14) @@ -273,18 +272,6 @@ GEM concurrent-ruby railties (>= 4.1) jwt (2.2.1) - kaminari (1.1.1) - activesupport (>= 4.1.0) - kaminari-actionview (= 1.1.1) - kaminari-activerecord (= 1.1.1) - kaminari-core (= 1.1.1) - kaminari-actionview (1.1.1) - actionview - kaminari-core (= 1.1.1) - kaminari-activerecord (1.1.1) - activerecord - kaminari-core (= 1.1.1) - kaminari-core (1.1.1) kgio (2.11.2) kramdown (2.1.0) launchy (2.4.3) @@ -550,6 +537,9 @@ GEM equalizer (~> 0.0.9) parser (~> 2.6.3) procto (~> 0.0.2) + validate_url (1.0.8) + activemodel (>= 3.0.0) + public_suffix warden (1.2.8) rack (>= 2.0.6) webdrivers (4.1.2) @@ -582,7 +572,6 @@ DEPENDENCIES bonsai-elasticsearch-rails bootstrap (>= 4.3.1) bootstrap-datepicker-rails - bootstrap-kaminari-views bootstrap_form (>= 4.2.0) bullet bundler (>= 1.1.5) @@ -604,6 +593,8 @@ DEPENDENCIES elasticsearch (< 7.0.0) factory_bot_rails faker + faraday + faraday_middleware figaro flickraw font-awesome-sass @@ -621,7 +612,6 @@ DEPENDENCIES jquery-ui-rails js-routes jsonapi-resources - kaminari leaflet-rails letter_opener listen @@ -662,6 +652,7 @@ DEPENDENCIES timecop uglifier unicorn + validate_url webdrivers webrat will_paginate diff --git a/app/assets/stylesheets/_crops.scss b/app/assets/stylesheets/_crops.scss index d56530bb5..2d72137b9 100644 --- a/app/assets/stylesheets/_crops.scss +++ b/app/assets/stylesheets/_crops.scss @@ -2,6 +2,41 @@ height: 1em; } +.crop-thumbnail { + .text { + bottom: 0; + color: $white; + margin: 0; + opacity: .9; + position: absolute; + text-align: center; + width: 100%; + + h3 { + background-color: $brown; + font-size: 1em; + } + + h5.crop-sci-name { + background-color: $beige; + color: $black; + font-size: .7em; + } + + a { + color: $white; + } + + a:hover { + color: $black; + } + + .img-card { + border: 5%; + } + } +} + .planting { .crop-card { height: 100%; diff --git a/app/assets/stylesheets/_homepage.scss b/app/assets/stylesheets/_homepage.scss index 4910436af..d33364c23 100644 --- a/app/assets/stylesheets/_homepage.scss +++ b/app/assets/stylesheets/_homepage.scss @@ -1,94 +1,17 @@ -// signup widget on homepage - -// let's condense the hero unit a little -.jumbotron { - background-color: darken($beige, 10%); - padding-bottom: 30px; - padding-top: 30px; - - // signup widget on homepage - .signup { - background-color: lighten($green, 40%); - border: 1px solid lighten($green, 20%); - border-radius: 6px; - line-height: 200%; - padding: 15px; - text-align: center; - } - - .info { - padding: .5em; - text-align: center; - } -} - -// info under the main heading on homepage -.homepage-cards { - display: flex; - flex: none; - flex-wrap: wrap; - margin: .5em; - - .card { - left: -.5em; - margin: .5em; - min-height: 100px; - padding: 0; - - %h3.crop-name { - font-size: 2em; - } - } - - .crop-card { - min-height: 80px; - width: 120px; - } - - .thumbnail { - margin: .5em; - } - - .img-card { - height: 150px; - } - -} - -.member-cards { - display: flex; - flex: none; - flex-wrap: wrap; - - .card { - margin: 1em; - width: 150px; - } -} // stats shown on homepage. eg. "999 members..." .stats { font-weight: bold; } -@include media-breakpoint-down(sm) { - .homepage-cards { - .seed-card { - min-height: 80px; - width: 100%; - } - - .member-card { - min-height: 80px; - width: 150px; - } +.crops, +.seeds, +.members { + .index-cards { + justify-content: center; } } -@include media-breakpoint-up(md) { - .homepage-cards { - .card { - width: 200px; - } - } +.homepage--list-item { + height: 100px; } diff --git a/app/assets/stylesheets/_members.scss b/app/assets/stylesheets/_members.scss index 76cf5eaef..1ab725311 100644 --- a/app/assets/stylesheets/_members.scss +++ b/app/assets/stylesheets/_members.scss @@ -21,10 +21,11 @@ background-color: lighten($green, 30%); border-radius: 25px; display: inline-block; - font-size: 1em; + font-size: .8em; height: 30px; line-height: 30px; padding: 0 25px; + white-space: nowrap; a { color: $black; @@ -55,3 +56,9 @@ height: 250px; width: 100%; } + +.badge-location { + background-color: darken($blue, 10%); + border-radius: 5%; + color: $white; +} diff --git a/app/assets/stylesheets/_photos.scss b/app/assets/stylesheets/_photos.scss index 5127f2336..831de851b 100644 --- a/app/assets/stylesheets/_photos.scss +++ b/app/assets/stylesheets/_photos.scss @@ -9,15 +9,6 @@ display: block; } -.photo-grid-item { - float: left; - - img { - display: block; - max-width: 100%; - } -} - .hero-photo { max-height: 500px; } diff --git a/app/assets/stylesheets/_plantings.scss b/app/assets/stylesheets/_plantings.scss index 820fd1329..897631e83 100755 --- a/app/assets/stylesheets/_plantings.scss +++ b/app/assets/stylesheets/_plantings.scss @@ -26,14 +26,6 @@ font-size: 200%; } } - .progress { - .progress-bar { - border-bottom-color: $green; - } - .progress-bar:after { - background-color: $beige; - } - } .planting-name { position: relative; @@ -42,7 +34,6 @@ } .planting-quick-actions { - background-color: $white; left: 0; position: absolute; top: 0; @@ -62,33 +53,3 @@ } } } - -.planting-facts { - display: flex; - flex-wrap: wrap; - flex: none; - - .planting-fact-card { - background: $white; - background: $white; - border-radius: 5%; - border: 1px solid lighten($green, 20%); - margin: 1em; - padding: 1em; - text-align: center; - width: 120px; - - strong { - font-align: center; - font-size: 4em; - } - - span { - display: block; - } - - img { - height: 50%; - } - } -} diff --git a/app/assets/stylesheets/_variables.scss b/app/assets/stylesheets/_variables.scss index 21fdceac3..5d9bdda5b 100644 --- a/app/assets/stylesheets/_variables.scss +++ b/app/assets/stylesheets/_variables.scss @@ -42,6 +42,20 @@ $dark: ( light: lighten($brown, 20%) ); + +$grid-breakpoints: ( + // Extra small screen / phone + xs: 0, + // Small screen / phone + sm: 576px, + // Medium screen / tablet + md: 768px, + // Large screen / desktop + lg: 1200px, + // Extra large screen / wide desktop + xl: 1800px +); + // Nav bar $navbar-default-bg: $brown; $navbar-default-bg-highlight: $brown; @@ -52,3 +66,7 @@ $navbar-default-link-active-color: darken($beige, 80%); $navbar-default-brand-color: lighten($green, 20%); $highest-level: 1070; + +$progress-height: 5em; +$progress-bar-color: $green; +$progress-bg: $white; \ No newline at end of file diff --git a/app/assets/stylesheets/overrides.scss b/app/assets/stylesheets/overrides.scss index 4e078f014..df44ca6e8 100755 --- a/app/assets/stylesheets/overrides.scss +++ b/app/assets/stylesheets/overrides.scss @@ -8,11 +8,6 @@ body { font-family: $font-family-sans-serif; } -section { - margin: 0; - padding-bottom: 1em; -} - .ellipsis { overflow: hidden; text-overflow: ellipsis; @@ -33,13 +28,8 @@ a:hover { text-decoration: none; } -.card a:hover { - background-color: $beige; - color: $blue; -} - -ul.list-inline > li.first { - padding-left: 0; +h1 { + font-size: 180%; } h2 { @@ -63,14 +53,93 @@ h3 { } } +section { + margin: .5em 0 0; + padding: 0 0 1em; + + h2 { + background-color: $green; + color: $white; + padding: .2em; + + a { + color: $white; + } + } + + .btn { + border: 1px solid $green; + } +} + +.layout-actions { + border: 1px solid lighten($green, 20%); + float: right; +} + .index-cards { display: flex; flex: none; flex-wrap: wrap; .card { - margin: 1em 1em 1em 0; + background: $white; + // border: 1px solid lighten($brown, 20%); + border-radius: 5%; + margin: .5em .5em .5em 0; width: 200px; + + .img-card { + border-top-left-radius: 5%; + border-top-right-radius: 5%; + } + } + + .card:hover { + background-color: $beige; + } +} + +.card { + margin-bottom: 1em; + + .img-card { + height: 180px; + object-fit: cover; + width: 100%; + } + + a:hover { + background-color: $beige; + color: $blue; + } +} + +.facts { + display: flex; + flex: none; + flex-wrap: wrap; + + .card { + margin: 1em; + max-width: 100%; + padding: 1em; + text-align: center; + width: 170px; + + strong { + display: block; + font-size: 2em; + text-align: center; + } + + span { + display: block; + } + + img { + height: 50%; + } } } @@ -78,12 +147,6 @@ img.img-icon { width: 1.2em; } -img.img-card { - height: 180px; - object-fit: cover; - width: 100%; -} - img.img-responsive { max-width: 100%; } @@ -95,23 +158,13 @@ img.avatar { z-index: 2; } -// this is used for eg. crops and members index pages -.six-across:nth-child(6n+1) { - margin-left: 0; -} - -.three-across:nth-child(3n+1) { - clear: both; - margin-left: 0; -} - -.card { - margin-bottom: 1em -} - .progress { border-radius: 0; - + height: 2em; + .progress-bar { + height: 2em; + background-color: $progress-bar-color + } .progress-bar-text { text-align: center; } @@ -154,7 +207,9 @@ footer { // ensure footer is pushed to bottom of browser window #maincontainer { + max-width: 2500px; min-height: 80%; + padding: 1em; } // Autosuggest @@ -219,30 +274,6 @@ ul.thumbnail-buttons { visibility: visible; } -.container { - max-width: 1500px; -} - -// Small devices (landscape phones, less than 768px) -@include media-breakpoint-down(md) { - .planting-thumbnail { - dl.planting-attributes { - width: 100%; - - dt { - text-align: left; - width: 120px; - } - - dd { - margin-left: auto; - padding-left: 120px; - } - } - } -} - - .form-page { text-align: center; @@ -253,10 +284,32 @@ ul.thumbnail-buttons { padding: 1em; text-align: center; } +} - .crop-card { - width: 100px; +.jumbotron { + background-color: $beige; + margin-bottom: 1em; + padding-bottom: 30px; + padding-top: 30px; + + // signup widget on homepage + .signup { + background-color: lighten($green, 40%); + border: 1px solid lighten($green, 20%); + border-radius: 6px; + line-height: 200%; + padding: 15px; + text-align: center; } + + .info { + padding: .5em; + text-align: center; + } +} + +.breadcrumb { + background-color: $beige; } // Overrides applying only to mobile view. This must be at the end of the overrides file. @@ -264,6 +317,23 @@ ul.thumbnail-buttons { @include media-breakpoint-down(xs) { #maincontainer { width: 100%; + padding: 10px; + } + + h1 { + font-size: 200%; + } + + h2 { + font-size: 130%; + } + + h3 { + font-size: 120%; + } + + .card-title { + margin-bottom: 0; } .sidebar { @@ -272,7 +342,7 @@ ul.thumbnail-buttons { padding-left: 0; } - #map { + .map { height: 300px; } @@ -289,20 +359,32 @@ ul.thumbnail-buttons { } } - #maincontainer { - padding: 10px; + .nav .btn { + background-color: lighten($green, 50%); + width: 100%; } - .homepage-cards { - .crop-card { - width: 50px; - } + section .btn { + width: 100%; } .index-cards { .card { - width: 100%; - margin: 0.5em; + margin: .2em; + width: 45%; + + // Shrink title to fit more on page + .card-title { + font-size: 1em; + } + + // Restrict height of image when on smaller screens + .img-card { + height: 100px; + object-fit: cover; + width: 100%; + } + } } } diff --git a/app/controllers/charts/gardens_controller.rb b/app/controllers/charts/gardens_controller.rb index 8b67bc106..b9d25bb53 100644 --- a/app/controllers/charts/gardens_controller.rb +++ b/app/controllers/charts/gardens_controller.rb @@ -7,7 +7,7 @@ module Charts @garden.plantings.where.not(planted_at: nil) .order(finished_at: :desc).each do |p| # use finished_at if we have it, otherwise use predictions - finish = p.finished_at.presence || p.finish_predicted_at + finish = p.finished_at.presence || p.finish_predicted_at || Time.zone.today.to_date @data << [p.crop.name, p.planted_at, finish] if finish.present? end render json: @data diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 8a02e195c..65a559423 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -4,7 +4,7 @@ class CropsController < ApplicationController before_action :authenticate_member!, except: %i(index hierarchy search show) load_and_authorize_resource skip_authorize_resource only: %i(hierarchy search) - respond_to :html, :json, :rss, :csv + respond_to :html, :json, :rss, :csv, :svg responders :flash def index @@ -35,8 +35,14 @@ class CropsController < ApplicationController respond_with @crops end + def openfarm + @crop = Crop.find(params[:crop_slug]) + @crop.update_openfarm_data! + respond_with @crop, location: @crop + end + def hierarchy - @crops = Crop.toplevel + @crops = Crop.toplevel.order(:name) respond_with @crops end @@ -60,6 +66,7 @@ class CropsController < ApplicationController respond_to do |format| format.html + format.svg { send_data(@crop.svg_icon, type: "image/svg+xml", disposition: "inline") } format.json { render json: @crop.to_json(crop_json_fields) } end end @@ -95,15 +102,20 @@ class CropsController < ApplicationController def update @crop = Crop.find_by!(slug: params[:slug]) - previous_status = @crop.approval_status - @crop.creator = current_member if previous_status == "pending" + if can?(:wrangle, @crop) + @crop.approval_status = 'rejected' if params.fetch("reject", false) + @crop.approval_status = 'approved' if params.fetch("approve", false) + end + @crop.creator = current_member if @crop.approval_status == "pending" if @crop.update(crop_params) recreate_names('alt_name', 'alternate') recreate_names('sci_name', 'scientific') - notifier.deliver_now! if previous_status == "pending" + notifier.deliver_now! if @crop.approval_status_changed?(from: "pending", to: "approved") + else + @crop.approval_status = @crop.approval_status_was end respond_with @crop @@ -162,18 +174,18 @@ class CropsController < ApplicationController end def crop_params - params.require(:crop).permit(:en_wikipedia_url, + params.require(:crop).permit( + :en_wikipedia_url, :name, :parent_id, - :creator_id, :perennial, - :approval_status, :request_notes, :reason_for_rejection, :rejection_notes, scientific_names_attributes: %i(scientific_name _destroy - id)) + id) + ) end def filename @@ -198,7 +210,7 @@ class CropsController < ApplicationController q = Crop.approved.includes(:scientific_names, plantings: :photos) q = q.popular unless @sort == 'alpha' q.order(Arel.sql("LOWER(crops.name)")) - .includes(:photos).paginate(page: params[:page]) + .includes(:photos).paginate(page: params[:page], per_page: 30) end def requested_crops diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 47870d38d..b8de4b54e 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,5 +1,5 @@ class SessionsController < Devise::SessionsController - respond_to :json + respond_to :html, :json def create super do |_resource| diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index a691b5218..b21cf0757 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -73,6 +73,16 @@ module IconsHelper icon('fas', 'heart') end + def crop_icon(crop) + if crop.svg_icon.present? + image_tag(crop_path(crop, format: 'svg'), class: 'crop-icon') + elsif crop.parent.present? + crop_icon(crop.parent) + else + planting_icon + end + end + def sunniness_icon(sunniness) if sunniness.present? image_tag("sunniness_#{sunniness}.png", class: 'img', alt: sunniness, width: 55) diff --git a/app/helpers/photos_helper.rb b/app/helpers/photos_helper.rb index 9e1053820..dc6d88348 100644 --- a/app/helpers/photos_helper.rb +++ b/app/helpers/photos_helper.rb @@ -1,37 +1,47 @@ module PhotosHelper - def crop_image_path(crop, full_size: false) - photo_or_placeholder(crop, full_size: full_size) - end - - def garden_image_path(garden, full_size: false) - photo_or_placeholder(garden, full_size: full_size) - end - - def planting_image_path(planting, full_size: false) - photo_or_placeholder(planting, full_size: full_size) - end - - def harvest_image_path(harvest, full_size: false) - photo_or_placeholder(harvest, full_size: full_size) - end - - def seed_image_path(seed, full_size: false) - photo_or_placeholder(seed, full_size: full_size) - end - - private - - def photo_or_placeholder(item, full_size: false) - if item.default_photo.present? - item_photo(item, full_size: full_size) + def crop_image_path(crop) + if crop.default_photo.present? + # The flickr thumbnails are too small, use full size + if crop.default_photo.source == 'flickr' + crop.default_photo.fullsize_url + else + crop.default_photo.thumbnail_url + end else placeholder_image end end - def item_photo(item, full_size:) - photo = item.default_photo - full_size ? photo.fullsize_url : photo.thumbnail_url + def garden_image_path(garden) + photo_or_placeholder(garden) + end + + def planting_image_path(planting) + photo_or_placeholder(planting) + end + + def harvest_image_path(harvest) + photo_or_placeholder(harvest) + end + + def seed_image_path(seed) + photo_or_placeholder(seed) + end + + private + + def photo_or_placeholder(item) + if item.default_photo.present? + item_photo(item) + elsif item.respond_to?(:crop) + crop_image_path(item.crop) + else + placeholder_image + end + end + + def item_photo(item) + item.default_photo.fullsize_url end def placeholder_image diff --git a/app/models/ability.rb b/app/models/ability.rb index f8b05d3cf..b2231e64b 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -76,6 +76,7 @@ class Ability can :manage, Crop can :manage, ScientificName can :manage, AlternateName + can :openfarm, Crop end # any member can create a crop provisionally diff --git a/app/models/concerns/open_farm_data.rb b/app/models/concerns/open_farm_data.rb new file mode 100644 index 000000000..f56c0fa66 --- /dev/null +++ b/app/models/concerns/open_farm_data.rb @@ -0,0 +1,75 @@ +module OpenFarmData + extend ActiveSupport::Concern + + included do # rubocop:disable Metrics/BlockLength + def update_openfarm_data! + OpenfarmService.new.update_crop(self) + end + + def of_photo + fetch_attr('main_image_path') + end + + def height + fetch_attr('height') + end + + def spread + fetch_attr('spread') + end + + def svg_icon + fetch_attr('svg_icon') + end + + def tags_array + fetch_attr('tags_array') + end + + def description + fetch_attr('description') + end + + def row_spacing + fetch_attr('row_spacing') + end + + def common_names + fetch_attr('common_names') + end + + def guides_count + fetch_attr('guides_count') + end + + def binomial_name + fetch_attr('binomial_name') + end + + def sowing_method + fetch_attr('sowing_method') + end + + def main_image_path + fetch_attr('main_image_path') + end + + def sun_requirements + fetch_attr('sun_requirements') + end + + def growing_degree_days + fetch_attr('growing_degree_days') + end + + def processing_pictures + fetch_attr('processing_pictures') + end + end + + def fetch_attr(key) + return if openfarm_data.blank? + + openfarm_data.fetch('attributes', {}).fetch(key, nil) + end +end diff --git a/app/models/crop.rb b/app/models/crop.rb index 1c787c8f9..a9dfabe52 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -1,10 +1,14 @@ class Crop < ApplicationRecord extend FriendlyId include PhotoCapable + include OpenFarmData friendly_id :name, use: %i(slugged finders) ## ## Relationships + belongs_to :creator, class_name: 'Member', optional: true, inverse_of: :created_crops + belongs_to :requester, class_name: 'Member', optional: true, inverse_of: :requested_crops + belongs_to :parent, class_name: 'Crop', optional: true, inverse_of: :varieties has_many :scientific_names, dependent: :delete_all accepts_nested_attributes_for :scientific_names, allow_destroy: true, reject_if: :all_blank has_many :alternate_names, dependent: :delete_all @@ -14,11 +18,8 @@ class Crop < ApplicationRecord has_many :photo_associations, dependent: :delete_all has_many :photos, through: :photo_associations has_many :plant_parts, -> { joins_members.distinct.order("plant_parts.name") }, through: :harvests - belongs_to :creator, class_name: 'Member', optional: true, inverse_of: :created_crops - belongs_to :requester, class_name: 'Member', optional: true, inverse_of: :requested_crops - belongs_to :parent, class_name: 'Crop', optional: true, inverse_of: :varieties has_many :varieties, class_name: 'Crop', foreign_key: 'parent_id', dependent: :nullify, inverse_of: :parent - has_many :crop_companions, foreign_key: :crop_a_id, inverse_of: :crop_a, dependent: :delete_all + has_many :crop_companions, foreign_key: :crop_a_id, dependent: :delete_all, inverse_of: :crop_a has_many :companions, through: :crop_companions, source: :crop_b, class_name: 'Crop' has_many :crop_posts, dependent: :delete_all has_many :posts, through: :crop_posts, dependent: :delete_all @@ -42,8 +43,6 @@ class Crop < ApplicationRecord ## Validations # Reasons are only necessary when rejecting validates :reason_for_rejection, presence: true, if: :rejected? - ## This validation addresses a race condition - validate :approval_status_cannot_be_changed_again validate :must_be_rejected_if_rejected_reasons_present validate :must_have_meaningful_reason_for_rejection ## Wikipedia urls are only necessary when approving a crop @@ -164,6 +163,10 @@ class Crop < ApplicationRecord } end + def fetch_from_openfarm! + OpenfarmService.new.update_crop(self) + end + private def count_uses_of_property(col_name) @@ -174,14 +177,6 @@ class Crop < ApplicationRecord .count end - # Custom validations - def approval_status_cannot_be_changed_again - previous = previous_changes.include?(:approval_status) ? previous_changes.approval_status : {} - return unless previous.include?(:rejected) || previous.include?(:approved) - - errors.add(:approval_status, "has already been set to #{approval_status}") - end - def must_be_rejected_if_rejected_reasons_present return if rejected? return unless reason_for_rejection.present? || rejection_notes.present? diff --git a/app/models/photo.rb b/app/models/photo.rb index 304c43c6f..a1e7099c1 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -2,11 +2,14 @@ class Photo < ApplicationRecord include Likeable include Ownable - PHOTO_CAPABLE = %w(Garden Planting Harvest Seed Post).freeze + PHOTO_CAPABLE = %w(Garden Planting Harvest Seed Post Crop).freeze has_many :photo_associations, foreign_key: :photo_id, dependent: :delete_all, inverse_of: :photo has_many :crops, through: :photo_associations + validates :fullsize_url, url: true, uniqueness: true + validates :thumbnail_url, url: true, uniqueness: true + # creates a relationship for each assignee type PHOTO_CAPABLE.each do |type| has_many type.downcase.pluralize.to_s.to_sym, diff --git a/app/models/photo_association.rb b/app/models/photo_association.rb index 24eb79e80..89e495b0f 100644 --- a/app/models/photo_association.rb +++ b/app/models/photo_association.rb @@ -18,12 +18,18 @@ class PhotoAssociation < ApplicationRecord end def set_crop - self.crop_id = photographable.crop_id if %w(Planting Seed Harvest).include?(photographable_type) + if %w(Planting Seed Harvest).include?(photographable_type) + self.crop_id = photographable.crop_id + elsif photographable_type == 'Crop' + self.crop_id = photographable_id + end end private def photo_and_item_have_same_owner + return unless photographable_type != 'Crop' + errors.add(:photo, "must have same owner as item it links to") unless photographable.owner_id == photo.owner_id end end diff --git a/app/services/openfarm_service.rb b/app/services/openfarm_service.rb new file mode 100644 index 000000000..b9cd243c6 --- /dev/null +++ b/app/services/openfarm_service.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true + +BASE = 'https://openfarm.cc/api/v1/' +# BASE = 'http://127.0.0.1:3000/api/v1/' + +class OpenfarmService + def initialize + @cropbot = Member.find_by(login_name: 'cropbot') + end + + def import! + Crop.all.order(updated_at: :desc).each do |crop| + Rails.logger.debug("#{crop.id}, #{crop.name}") + update_crop(crop) if crop.valid? + end + end + + def update_crop(crop) + openfarm_record = fetch(crop.name) + if openfarm_record.present? && openfarm_record.is_a?(String) + Rails.logger.info(openfarm_record) + elsif openfarm_record.present? && openfarm_record.fetch('data', false) + crop.update! openfarm_data: openfarm_record.fetch('data', false) + save_companions(crop, openfarm_record) + save_photos(crop) + else + Rails.logger.debug "\tcrop not found on Open Farm" + crop.update!(openfarm_data: false) + end + end + + def save_companions(crop, openfarm_record) + companions = openfarm_record.fetch('data').fetch('relationships').fetch('companions').fetch('data') + crops = openfarm_record.fetch('included', []).select { |rec| rec["type"] == 'crops' } + CropCompanion.transaction do + companions.each do |com| + companion_crop_hash = crops.detect { |c| c.fetch('id') == com.fetch('id') } + companion_crop_name = companion_crop_hash.fetch('attributes').fetch('name').downcase + companion_crop = Crop.where('lower(name) = ?', companion_crop_name).first + companion_crop = Crop.create!(name: companion_crop_name, requester: @cropbot, approval_status: "pending") if companion_crop.nil? + crop.companions << companion_crop unless crop.companions.where(id: companion_crop.id).any? + end + end + end + + def save_photos(crop) + pictures = fetch_pictures(crop.name) + pictures.each do |picture| + data = picture.fetch('attributes') + Rails.logger.debug(data) + next unless data.fetch('image_url').start_with? 'http' + next if Photo.find_by(source_id: picture.fetch('id'), source: 'openfarm') + + photo = Photo.new( + source_id: picture.fetch('id'), + source: 'openfarm', + owner: @cropbot, + thumbnail_url: data.fetch('thumbnail_url'), + fullsize_url: data.fetch('image_url'), + title: 'Open Farm photo', + license_name: 'No rights reserved', + link_url: "https://openfarm.cc/en/crops/#{name_to_slug(crop.name)}" + ) + if photo.valid? + Photo.transaction do + photo.save + PhotoAssociation.find_or_create_by! photo: photo, photographable: crop + end + Rails.logger.debug "\t saved photo #{photo.id} #{photo.source_id}" + else + Rails.logger.warn "Photo not valid" + end + end + end + + def fetch(name) + conn.get("crops/#{name_to_slug(name)}.json").body + rescue NoMethodError + Rails.logger.debug "error fetching crop" + Rails.logger.debug "BODY: " + Rails.logger.debug body + end + + def name_to_slug(name) + CGI.escape(name.gsub(' ', '-').downcase) + end + + def fetch_all(page) + conn.get("crops.json?page=#{page}").body.fetch('data', {}) + end + + def fetch_pictures(name) + body = conn.get("crops/#{name_to_slug(name)}/pictures.json").body + body.fetch('data', false) + rescue StandardError + Rails.logger.debug "Error fetching photos" + Rails.logger.debug [] + end + + private + + def conn + Faraday.new BASE do |conn| + conn.response :json, content_type: /\bjson$/ + conn.adapter Faraday.default_adapter + end + end +end diff --git a/app/views/crops/_actions.html.haml b/app/views/crops/_actions.html.haml index 60d337c77..1fd159662 100644 --- a/app/views/crops/_actions.html.haml +++ b/app/views/crops/_actions.html.haml @@ -1,16 +1,16 @@ - if @crop.approved? && signed_in? - .crop-actions + .nav.crop-actions - if can? :create, Planting - = link_to new_planting_path(crop_id: crop.id), class: 'btn btn-sm' do + = link_to new_planting_path(crop_id: crop.id), class: 'list-group-item btn' do = planting_icon = t('buttons.plant_crop', crop_name: crop.name) - if can? :create, Harvest - = link_to new_harvest_path(crop_id: crop.id), class: 'btn btn-sm' do + = link_to new_harvest_path(crop_id: crop.id), class: 'list-group-item btn' do = harvest_icon = t('buttons.harvest_crop', crop_name: crop.name) - if can? :create, Seed - = link_to new_seed_path(crop_id: crop.id), class: 'btn btn-sm' do + = link_to new_seed_path(crop_id: crop.id), class: 'list-group-item btn' do = seed_icon = t('buttons.add_seed_to_stash', crop_name: crop.name) diff --git a/app/views/crops/_alternate_names.html.haml b/app/views/crops/_alternate_names.html.haml index 5d75b81f3..04c4314fc 100644 --- a/app/views/crops/_alternate_names.html.haml +++ b/app/views/crops/_alternate_names.html.haml @@ -1,26 +1,23 @@ .alternate_names %h4 Alternate names - - if crop.alternate_names.empty? - %p None known. - - else - %ul.list-group.list-group-flush - - crop.alternate_names.each do |an| - %li.list-group-item.d-flex.justify-content-between.align-items-center - - if can? :edit, an - .dropdown.planting-actions - %a#crop-actions-altnames.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :type => "button", :href => '#'} - = an.name - .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "crop-actions-altnames"} - - if can? :edit, an - = link_to edit_alternate_name_path(an), class: 'dropdown-item' do - = edit_icon - = t('.edit') - - if can? :destroy, an - = link_to an, method: :delete, data: { confirm: 'Are you sure?' }, class: 'dropdown-item' do - = delete_icon - = t('.delete') - - else + - if crop.alternate_names.any? + - crop.alternate_names.each do |an| + - if can? :edit, an + .dropdown.planting-actions + %a#crop-actions-altnames.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :type => "button", :href => '#'} = an.name + .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "crop-actions-altnames"} + - if can? :edit, an + = link_to edit_alternate_name_path(an), class: 'dropdown-item' do + = edit_icon + = t('.edit') + - if can? :destroy, an + = link_to an, method: :delete, data: { confirm: 'Are you sure?' }, class: 'dropdown-item' do + = delete_icon + = t('.delete') + - else + .badge= an.name + %p.text-right - if can? :edit, crop diff --git a/app/views/crops/_crop.html.haml b/app/views/crops/_crop.html.haml index 40bd4e508..83e82ffb0 100644 --- a/app/views/crops/_crop.html.haml +++ b/app/views/crops/_crop.html.haml @@ -1,6 +1,6 @@ .card.card-crop .crop-image - = link_to image_tag(crop_image_path(crop, full_size: true), + = link_to image_tag(crop_image_path(crop), alt: '', class: 'img img-card'), crop diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index 4c087ff5d..a0f981959 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -94,8 +94,8 @@ -# Now, for crop wranglers, let's have approval/rejection at the bottom of the page - if can?(:wrangle, @crop) && @crop.requester - %h2 Approve or reject pending crops - = f.select(:approval_status, @crop.approval_statuses, {}) + -# %h2 Approve or reject pending crops + -# = f.select(:approval_status, @crop.approval_statuses, {}) = f.select(:reason_for_rejection, @crop.reasons_for_rejection, include_blank: true) = f.text_area :rejection_notes, rows: 3 @@ -103,4 +103,9 @@ Please provide additional notes why this crop request was rejected if the above reasons do not apply. .card-footer - .text-right= f.submit 'Save' + .text-right + - if @crop.approved? + = f.submit 'Save' + - else + = f.submit 'Reject', class: 'btn btn-danger', name: 'reject' + = f.submit 'Approve and save', class: 'btn btn-success', name: 'approve' diff --git a/app/views/crops/_grown_for.html.haml b/app/views/crops/_grown_for.html.haml index 0544bdb5f..dccb4821b 100644 --- a/app/views/crops/_grown_for.html.haml +++ b/app/views/crops/_grown_for.html.haml @@ -1,8 +1,6 @@ -%p - %strong Grown for: - - if crop.harvests.empty? - not known. - - else +- if crop.harvests.any? + %p + %strong Grown for: - crop.popular_plant_parts.each do |plant_part, frequency| - id, name = plant_part = link_to name, plant_part_path(id: id) diff --git a/app/views/crops/_hierarchy.html.haml b/app/views/crops/_hierarchy.html.haml index a4b760354..989c5145b 100644 --- a/app/views/crops/_hierarchy.html.haml +++ b/app/views/crops/_hierarchy.html.haml @@ -4,8 +4,8 @@ - max = 0 # list all without "show all" toggle button - display_crops.each do |c| %li.crop-hierarchy{ class: (max != 0 && @count >= max) || !c.approved? ? ['hide', 'toggle'] : [] } - = link_to c, c + = render 'crops/tiny', crop: c - @count += 1 - if c.varieties.present? - - c.varieties.each do |v| + - c.varieties.order(:name).each do |v| = render partial: 'hierarchy', locals: { display_crops: [v], max: max } diff --git a/app/views/crops/_info.haml b/app/views/crops/_info.haml new file mode 100644 index 000000000..efaf693cc --- /dev/null +++ b/app/views/crops/_info.haml @@ -0,0 +1,25 @@ +.row + .col-md-9 + %h1 + = crop_icon(@crop) + %strong= @crop.name.titleize + - unless @crop.approved? + %badge.badge-warning=@crop.approval_status + %small.text-muted= @crop.default_scientific_name + - if @crop.sowing_method.present? + %h2= @crop.sowing_method + - if @crop.sun_requirements.present? + %p + Plant in #{@crop.sun_requirements} + %p.text-muted + - if !@crop.plantings.empty? + #{@crop.name.titleize} has been planted + = pluralize(@crop.plantings.size, "time") + by #{ENV['GROWSTUFF_SITE_NAME']} members. + - else + Nobody is growing this yet. You could be the first! + - if @crop.description.present? + %p= @crop.description + .col-md-3 + = image_tag crop_image_path(@crop), + class: 'img-responsive shadow rounded crop-hero-photo', alt: 'photo of crop' diff --git a/app/views/crops/_photos.html.haml b/app/views/crops/_photos.html.haml index 71358d541..8fe35a6cf 100644 --- a/app/views/crops/_photos.html.haml +++ b/app/views/crops/_photos.html.haml @@ -1,9 +1,7 @@ - if @crop.photos.size.positive? %h2 #{photo_icon} Photos - - [Planting, Harvest, Seed].each do |model_name| + - [Crop, Planting, Harvest, Seed].each do |model_name| - if photos.by_model(model_name).size.positive? %h3 #{@crop.name.capitalize} #{t("activerecord.models.#{model_name.to_s.downcase}.other")} - = render 'photos/gallery', photos: photos.by_model(model_name).order(likes_count: :desc).limit(8) - + = render 'photos/gallery', photos: photos.by_model(model_name).order(likes_count: :desc).limit(5) = link_to 'more photos »', crop_photos_path(@crop), class: 'btn' - %hr/ diff --git a/app/views/crops/_planting_advice.html.haml b/app/views/crops/_planting_advice.html.haml index 4a444794a..a554a7058 100644 --- a/app/views/crops/_planting_advice.html.haml +++ b/app/views/crops/_planting_advice.html.haml @@ -1,15 +1,6 @@ -%p - %strong Plant from: - - if crop.planted_from.empty? - not known. - - else - - planted_from = crop.planted_from.sort_by { |_, freq| freq }.reverse - = planted_from.map { |s, freq| "#{s} (#{freq})" }.join(", ") +- if crop.guides_count.present? && crop.guides_count.positive? + %p + There are + = link_to "https://openfarm.cc/en/crops/#{CGI.escape @crop.name.gsub(' ', '-').downcase}" do + #{crop.guides_count} growing guides on Open Farm -%p - %strong Plant in: - - if crop.sunniness.empty? - not known. - - else - - sunniness = crop.sunniness.sort_by { |_, freq| freq }.reverse - = sunniness.map { |s, freq| "#{s} (#{freq})" }.join(", ") diff --git a/app/views/crops/_posts.html.haml b/app/views/crops/_posts.html.haml index 2012f642a..1fcfea2fc 100644 --- a/app/views/crops/_posts.html.haml +++ b/app/views/crops/_posts.html.haml @@ -11,13 +11,12 @@ = render partial: "shared/signin_signup", locals: { to: "post your tips and experiences growing #{crop.name.pluralize}" } - else - .pagination - = page_entries_info @posts - = render 'layouts/pagination', collection: @posts - - @posts.each do |post| - = render 'posts/preview', post: post - .pagination - = page_entries_info @posts - = render 'layouts/pagination', collection: @posts + = render 'layouts/pagination', collection: @posts + + .index-cards + - @posts.each do |post| + = render 'posts/preview', post: post + + = render 'layouts/pagination', collection: @posts diff --git a/app/views/crops/_predictions.html.haml b/app/views/crops/_predictions.html.haml index 82df172df..02e3bbacc 100644 --- a/app/views/crops/_predictions.html.haml +++ b/app/views/crops/_predictions.html.haml @@ -1,49 +1,58 @@ -%h3 +%h2 = icon 'fas', 'magic' Predictions -.card-deck.mx-auto.predictions +.index-cards.facts - unless crop.perennial.nil? - .col - .card.predictions-card - .card-body.text-center - %h3 - = link_to 'https://en.wikipedia.org/wiki/Annual_vs._perennial_plant_evolution' do - - if crop.perennial == true - Perennial - - elsif crop.perennial == false - Annual + .card.fact-card + .card-body.text-center + %h3 + = link_to 'https://en.wikipedia.org/wiki/Annual_vs._perennial_plant_evolution' do + - if crop.perennial == true + Perennial + - elsif crop.perennial == false + Annual - %p.display-1 - %i.far.fa-calendar + %strong + %i.far.fa-calendar - - if crop.perennial == true - %small living more than two years - - elsif crop.perennial == false - %small living and reproducing in a single year or less + - if crop.perennial == true + %small living more than two years + - elsif crop.perennial == false + %small living and reproducing in a single year or less - if crop.annual? && crop.median_lifespan.present? - .col - .card.predictions-card - .card-body.text-center - %h3 Median lifespan - %p.display-1= crop.median_lifespan - %i.fas.fa-sun-o.fa-5x.pt-3.amber-text - %span days + .card.fact-card + .card-body.text-center + %h3 Median lifespan + %strong= crop.median_lifespan + %i.fas.fa-sun-o.fa-5x.pt-3.amber-text + %span days - if crop.median_days_to_first_harvest.present? - .col - .card.predictions-card - .card-body.text-center - %h3 First harvest expected - %p.display-1= crop.median_days_to_first_harvest - %span days after planting + .card.fact-card + .card-body.text-center + %h3 First harvest expected + %strong= crop.median_days_to_first_harvest + %span days after planting - if crop.annual? && crop.median_days_to_last_harvest.present? - .col - .card.predictions-card - .card-body.text-center - %h3 Last harvest expected - %p.display-1= crop.median_days_to_last_harvest - %span days after planting + = render 'layouts/fact_card', + title: "Last harvest expected", + value: crop.median_days_to_last_harvest, + description: "days after planting" + - if crop.height.present? + = render 'layouts/fact_card', + title: 'Height', value: "#{crop.height}cm", description: nil + + - if crop.spread.present? + = render 'layouts/fact_card', + title: 'Spread', value: "#{crop.spread}cm", description: nil + + - if crop.row_spacing.present? + = render 'layouts/fact_card', + title: 'Row Spacing', value: "#{crop.row_spacing}cm", description: nil + - if crop.growing_degree_days.present? + = render 'layouts/fact_card', + title: 'Growing Degree Days', value: crop.growing_degree_days, description: nil diff --git a/app/views/crops/_scientific_names.html.haml b/app/views/crops/_scientific_names.html.haml index 66036e198..bf6ace250 100644 --- a/app/views/crops/_scientific_names.html.haml +++ b/app/views/crops/_scientific_names.html.haml @@ -3,22 +3,20 @@ - if crop.scientific_names.empty? %p None known. - else - %ul.list-group.list-group-flush - - crop.scientific_names.each do |sn| - %li.list-group-item.d-flex.justify-content-between.align-items-center - - if can? :edit, sn - .dropdown.planting-actions - %a#planting-actions-scinames.dropdown-toggle.card-link{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :type => "button", :href => '#'}= sn.name - .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "planting-actions-button"} - = link_to edit_scientific_name_path(sn), class: 'dropdown-item' do - = edit_icon - = t('.edit') - .dropdown-divider - = link_to sn, method: :delete, data: { confirm: 'Are you sure?' }, class: 'dropdown-item text-danger' do - = delete_icon - = t('.delete') - - else - = sn.name + - crop.scientific_names.each do |sn| + - if can? :edit, sn + .dropdown.planting-actions + %a#planting-actions-scinames.dropdown-toggle.card-link{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :type => "button", :href => '#'}= sn.name + .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "planting-actions-button"} + = link_to edit_scientific_name_path(sn), class: 'dropdown-item' do + = edit_icon + = t('.edit') + .dropdown-divider + = link_to sn, method: :delete, data: { confirm: 'Are you sure?' }, class: 'dropdown-item text-danger' do + = delete_icon + = t('.delete') + - else + .badge= sn.name %p.text-right - if can? :edit, crop diff --git a/app/views/crops/_thumbnail.html.haml b/app/views/crops/_thumbnail.html.haml index 3b1988283..39559e29c 100644 --- a/app/views/crops/_thumbnail.html.haml +++ b/app/views/crops/_thumbnail.html.haml @@ -1,10 +1,11 @@ -.card.card-crop - .crop-image - = link_to image_tag(crop_image_path(crop, full_size: true), - alt: crop.name, - class: 'img img-card'), - crop +.card.crop-thumbnail + = link_to image_tag(crop_image_path(crop), + alt: crop.name, + class: 'img img-card'), + crop - .card-body - %h3.text-center.crop-name= link_to crop, crop - %p.small.crop-sci-name.text-center= crop.default_scientific_name + .text + %h3.crop-name= link_to crop, crop + %h5.crop-sci-name +   + = crop.default_scientific_name diff --git a/app/views/crops/_tiny.html.haml b/app/views/crops/_tiny.html.haml index 4e18c5871..8b948a9cc 100644 --- a/app/views/crops/_tiny.html.haml +++ b/app/views/crops/_tiny.html.haml @@ -1,6 +1,7 @@ - if crop.approved? || can?(:wrangle, Crop) .crop-chip = link_to crop do + = crop_icon(crop) = crop.name - unless crop.approved? %badge.badge-warning= crop.approval_status diff --git a/app/views/crops/_varieties.html.haml b/app/views/crops/_varieties.html.haml index 2b3407388..e4a8b5f22 100644 --- a/app/views/crops/_varieties.html.haml +++ b/app/views/crops/_varieties.html.haml @@ -1,5 +1,5 @@ - if crop.varieties.size.positive? - %h3 Varieties - .row + %h2 Varieties + .index-cards - crop.varieties.order(:name).each do |v| - .col-md-2.six-across= render 'crops/thumbnail', crop: v \ No newline at end of file + = render 'crops/thumbnail', crop: v \ No newline at end of file diff --git a/app/views/crops/_wrangle.html.haml b/app/views/crops/_wrangle.html.haml index 7cedc4ca3..6c93c734d 100644 --- a/app/views/crops/_wrangle.html.haml +++ b/app/views/crops/_wrangle.html.haml @@ -1,6 +1,5 @@ - if can?(:edit, crop) || can?(:destroy, crop) .alert.alert-success{role: "alert"} - %h4 Crop wrangling %p You are a %strong CROP WRANGLER @@ -11,6 +10,10 @@ = edit_icon = t('.edit') + = link_to crop_openfarm_path(crop), method: :post, class: 'dropdown-item' do + = icon 'far', 'update' + Fetch data from OpenFarm + - if can? :destroy, crop .dropdown-divider = delete_button(crop, classes: 'dropdown-item text-danger') diff --git a/app/views/crops/index.html.haml b/app/views/crops/index.html.haml index e0eb151e1..07e0d37b7 100644 --- a/app/views/crops/index.html.haml +++ b/app/views/crops/index.html.haml @@ -24,15 +24,14 @@ label: 'Sort by' = f.submit "Show" -.pagination= render 'layouts/pagination', collection: @crops += render 'layouts/pagination', collection: @crops .crops - .row + .index-cards - @crops.each do |crop| - .col-6.col-md-3= render 'crops/thumbnail', crop: crop + = render 'crops/thumbnail', crop: crop - -.pagination= render 'layouts/pagination', collection: @crops += render 'layouts/pagination', collection: @crops %ul.list-inline %li The data on this page is available in the following formats: diff --git a/app/views/crops/requested.haml b/app/views/crops/requested.haml index bd0f1cfd5..931ee3de2 100644 --- a/app/views/crops/requested.haml +++ b/app/views/crops/requested.haml @@ -6,10 +6,9 @@ .pagination = will_paginate @requested -.row +.index-cards - @requested.each do |crop| - .col-md-2.six-across - = render partial: "thumbnail", locals: { crop: crop } + = render partial: "thumbnail", locals: { crop: crop } .pagination = will_paginate @requested diff --git a/app/views/crops/search.html.haml b/app/views/crops/search.html.haml index 1312f5d50..45610b70d 100644 --- a/app/views/crops/search.html.haml +++ b/app/views/crops/search.html.haml @@ -2,25 +2,23 @@ %li.breadcrumb-item= link_to 'Crops', crops_path %li.breadcrumb-item.active= link_to 'Search', search_crops_path(term: @term) -%section.crops-search-form - - - if @term - - content_for :title, "Crops matching \"#{@term}\"" - %h1 Crops matching "#{@term}" +- if @term + - content_for :title, "Crops matching \"#{@term}\"" + %h1 + Crops matching "#{@term}" - if @crops - %h2.text-muted Found #{@crops.size} total - - else - - content_for :title, "Crop search" - %h1 Crop search + %span.text-muted Found #{@crops.size} total +- else + - content_for :title, "Crop search" + %h1 Crop search - - = bootstrap_form_tag(url: search_crops_path, method: :get, html: { id: 'crop-search'}, layout: :inline) do |f| - = f.label :term, "Search crops:", class: 'sr-only' - = f.text_field 'term', class: 'search-query input-medium', - placeholder: 'Search crops', - label: 'crop', - value: @term - = f.submit "Search", class: 'btn btn-success' += bootstrap_form_tag(url: search_crops_path, method: :get, html: { id: 'crop-search'}, layout: :inline) do |f| + = f.label :term, "Search crops:", class: 'sr-only' + = f.text_field 'term', class: 'search-query input-medium', + placeholder: 'Search crops', + label: 'crop', + value: @term + = f.submit "Search", class: 'btn btn-success' - if @crops.empty? %h2 No results found @@ -32,12 +30,11 @@ instead. - else - .pagination= will_paginate @crops + = will_paginate @crops - .crops - .row - - @crops.each do |crop| - .col-6.col-md-3= render 'crops/thumbnail', crop: crop + .index-cards + - @crops.each do |crop| + = render 'crops/thumbnail', crop: crop - .pagination= will_paginate @crops + = will_paginate @crops diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index 131ab483a..68e841383 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -33,12 +33,13 @@ = image_tag crop_image_path(@crop), class: 'img-responsive shadow rounded crop-hero-photo', alt: 'photo of crop' +.jumbotron= render 'crops/info' + .row .col-md-9 - = render 'crops/actions', crop: @crop + %p= render 'crops/actions', crop: @crop .col-md-3 = render 'wrangle', crop: @crop - .row .col-md-9 %section.prediction= render 'predictions', crop: @crop diff --git a/app/views/follows/followers.html.haml b/app/views/follows/followers.html.haml index 3262de360..f6a005797 100644 --- a/app/views/follows/followers.html.haml +++ b/app/views/follows/followers.html.haml @@ -1,12 +1,11 @@ - content_for :title, "#{@member.login_name}'s followers" - -%h1.page-title #{@member.login_name}'s followers - = page_entries_info @followers = will_paginate @followers -.index-cards= render @followers +.index-cards + - @followers.each do |f| + .thumbnail= render partial: "members/thumbnail", locals: { member: f } = page_entries_info @followers = will_paginate @followers diff --git a/app/views/garden_types/index.html.haml b/app/views/garden_types/index.html.haml index 49352bc4c..d40e16ae9 100644 --- a/app/views/garden_types/index.html.haml +++ b/app/views/garden_types/index.html.haml @@ -4,10 +4,9 @@ #{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where. View any garden_type page to see which of our members have used it. -.row +.index-cards - @garden_types.each do |garden_type| - .col-md-2.six-across - = render partial: "thumbnail", locals: { garden_type: garden_type } + = render partial: "thumbnail", locals: { garden_type: garden_type } - if can? :create, GardenType %div diff --git a/app/views/gardens/_actions.html.haml b/app/views/gardens/_actions.html.haml index 715dcdf38..554d7e3fa 100644 --- a/app/views/gardens/_actions.html.haml +++ b/app/views/gardens/_actions.html.haml @@ -1,5 +1,5 @@ - if can?(:edit, garden) - .dropdown.float-right.garden-actions + .dropdown.garden-actions %a#garden-actions-button.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", type: "button", href: '#'} Actions .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "garden-actions-button"} - if can?(:edit, garden) diff --git a/app/views/gardens/_garden.html.haml b/app/views/gardens/_garden.html.haml new file mode 100644 index 000000000..bba2a0ee4 --- /dev/null +++ b/app/views/gardens/_garden.html.haml @@ -0,0 +1,5 @@ +.card + = link_to garden do + = image_tag garden_image_path(garden), class: 'img-card', alt: garden + .card-body.text-center + %h4.card-title= garden.name \ No newline at end of file diff --git a/app/views/gardens/index.html.haml b/app/views/gardens/index.html.haml index 0515ad7ef..ce0d67833 100644 --- a/app/views/gardens/index.html.haml +++ b/app/views/gardens/index.html.haml @@ -1,8 +1,7 @@ - content_for :title, @owner ? "#{@owner}'s gardens" : "Everyone's gardens" -%h1 - = @owner ? "#{@owner}'s gardens" : "Everyone's gardens" +%h1= @owner ? "#{@owner}'s gardens" : "Everyone's gardens" = render 'layouts/nav', model: Garden @@ -24,26 +23,19 @@ = link_to 'Add a garden', new_garden_path, class: 'btn btn-primary' - else - .row - .col-12= page_entries_info @gardens - .col-12= will_paginate @gardens + = page_entries_info @gardens + = will_paginate @gardens - @gardens.each do |garden| - %section.border-top - .row - .col-md-2.border-right - %h2 - %strong= link_to garden, garden - = render 'gardens/actions', garden: garden - %p - = pluralize(garden.plantings.active.size, "planting") - .col-md-10 - .row - - if garden.plantings.empty? - = garden_plant_something_button(garden, classes: 'btn btn-success') - - else - - garden.plantings.active.each do |planting| - .col-6.col-md-4.col-lg-3= render 'plantings/card', planting: planting - + %section + %h2 + = link_to garden.name, garden + = render 'gardens/actions', garden: garden + - if garden.plantings.any? + .index-cards + - garden.plantings.active.each do |planting| + = render planting, full: true + - else + No plantings .row .col-12= page_entries_info @gardens diff --git a/app/views/gardens/show.html.haml b/app/views/gardens/show.html.haml index cc97c141f..ae51892fa 100644 --- a/app/views/gardens/show.html.haml +++ b/app/views/gardens/show.html.haml @@ -46,14 +46,15 @@ Why not = link_to 'tell us more.', edit_garden_path(@garden) - .row - .col-md-12 - %section - %h3 Garden timeline - = timeline garden_timeline_path(@garden), adapter: "google" + - if @garden.plantings.where.not(planted_at: nil).any? + .row + .col-md-12 + %section + %h2 Garden timeline + = timeline garden_timeline_path(@garden), adapter: "google" %section - %h3.h3 Current plantings in garden + %h2 Current plantings in garden .index-cards - if @current_plantings.size.positive? - @current_plantings.each do |planting| @@ -62,7 +63,7 @@ .col-md-12 %p Nothing is currently planted here. %section - %h3.h3 Previously planted in this garden + %h2 Previously planted in this garden .index-cards - if @finished_plantings.size.positive? - @finished_plantings.each do |planting| @@ -72,7 +73,7 @@ .col-md-3 .card .card-image - = image_tag garden_image_path(@garden, full_size: true), class: 'img-card', alt: 'photo of this garden' + = image_tag garden_image_path(@garden), class: 'img-card', alt: 'photo of this garden' .card-body %h4 About this garden %p @@ -86,7 +87,7 @@ %p %strong Area: = pluralize(@garden.area, @garden.area_unit) - %hr/ + .card .card-header %h4 #{@garden.owner}'s gardens @@ -120,7 +121,8 @@ = add_photo_button(@garden) - if @garden.photos.size.positive? - %h3= localize_plural(@garden.photos, Photo) - .row - - @garden.photos.includes(:owner).each do |photo| - .col-xs-6= render 'photos/thumbnail', photo: photo + %section.photos + %h2= localize_plural(@garden.photos, Photo) + .index-cards + - @garden.photos.includes(:owner).each do |photo| + = render 'photos/thumbnail', photo: photo diff --git a/app/views/harvests/_actions.html.haml b/app/views/harvests/_actions.html.haml index 7cb6ca9a0..cafe42811 100644 --- a/app/views/harvests/_actions.html.haml +++ b/app/views/harvests/_actions.html.haml @@ -1,6 +1,6 @@ - if can?(:edit, harvest) - .dropdown.float-right.harvest-actions - %a#harvest-actions-button.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", type: "button", href: '#'} Actions + .dropdown.harvest-actions + %a#harvest-actions-button.btn.btn-info.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", type: "button", href: '#'} Actions .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "harvest-actions-button"} = harvest_edit_button(harvest, classes: 'dropdown-item') = add_photo_button(harvest, classes: 'dropdown-item') diff --git a/app/views/harvests/_card.html.haml b/app/views/harvests/_card.html.haml index 2cb4ff07b..51d077338 100644 --- a/app/views/harvests/_card.html.haml +++ b/app/views/harvests/_card.html.haml @@ -1,17 +1,16 @@ .card = link_to harvest do - = image_tag harvest_image_path(harvest, full_size: true), alt: harvest, class: 'img-card' + = image_tag harvest_image_path(harvest), alt: harvest, class: 'img-card' .card-body %h5 - %strong= link_to "#{harvest.crop} #{harvest.plant_part}", harvest - %span.badge.badge-pill.badge-info= link_to harvest.plant_part, harvest.plant_part - + = crop_icon(harvest.crop) + %strong + = link_to harvest.crop, harvest + %span.badge.badge-pill= link_to harvest.plant_part, harvest.plant_part - if harvest.planting.present? %p.card-text %small.text-muted Harvested from = link_to harvest.planting, harvest.planting .card-footer - %p - .float-left= link_to harvest.owner, harvest.owner - .float-right=render 'members/tiny', member: harvest.owner \ No newline at end of file + .float-right=render 'members/tiny', member: harvest.owner \ No newline at end of file diff --git a/app/views/harvests/_owner.html.haml b/app/views/harvests/_owner.html.haml index f51da33f8..977743c15 100644 --- a/app/views/harvests/_owner.html.haml +++ b/app/views/harvests/_owner.html.haml @@ -1,18 +1,19 @@ -.well - .row - .col-md-6 - %h4 - Harvested by - = link_to harvest.owner, harvest.owner - = link_to "view all #{harvest.owner}'s harvests", member_gardens_path(harvest.owner) +.card + .card-body + .row + .col-md-6 + %h4 + Harvested by + = link_to harvest.owner, harvest.owner + = link_to "view all #{harvest.owner}'s harvests", member_harvests_path(harvest.owner) - - if harvest.planting.present? - %p - Harvested from - = link_to harvest.planting, harvest.planting - - if harvest.owner.location - %p - %small - View other harvests, members and more near - = link_to harvest.owner.location, place_path(harvest.owner.location, anchor: "harvests") - .col-md-6= render "members/avatar", member: harvest.owner \ No newline at end of file + - if harvest.planting.present? + %p + Harvested from + = link_to harvest.planting, harvest.planting + - if harvest.owner.location + %p + %small + View other harvests, members and more near + = link_to harvest.owner.location, place_path(harvest.owner.location, anchor: "harvests") + .col-md-6= render "members/avatar", member: harvest.owner \ No newline at end of file diff --git a/app/views/harvests/_planting.haml b/app/views/harvests/_planting.haml index ae2d94b9c..5e1eaafe8 100644 --- a/app/views/harvests/_planting.haml +++ b/app/views/harvests/_planting.haml @@ -1,15 +1,7 @@ -- if @harvest.planting - = link_to "#{@harvest.planting.crop.name} planted on #{@harvest.planting.planted_at}", - planting_path(@harvest.planting) - in - = link_to @harvest.planting.garden, garden_path(@harvest.planting.garden) -- elsif @matching_plantings && @matching_plantings.any? && @harvest.owner == current_member - +- if @harvest.planting.nil? && @matching_plantings && @matching_plantings.any? && @harvest.owner == current_member .alert.alert-info{role: "alert"} = bootstrap_form_for(@harvest) do |f| Is this from one of these plantings? - @matching_plantings.each do |planting| = f.radio_button :planting_id, planting.id, label: planting = f.submit "save", class: 'btn btn-sm' -- else - Unknown diff --git a/app/views/harvests/index.html.haml b/app/views/harvests/index.html.haml index 3434f4e92..527ce0e56 100644 --- a/app/views/harvests/index.html.haml +++ b/app/views/harvests/index.html.haml @@ -32,13 +32,11 @@ = page_entries_info @harvests = will_paginate @harvests - %ul.list-inline - %li The data on this page is available in the following formats: - - if @owner - %li= link_to "RSS", member_harvests_path(@owner, format: 'rss') - %li= link_to "CSV", member_harvests_path(@owner, format: 'csv') - %li= link_to "JSON", member_harvests_path(@owner, format: 'json') - - else - %li= link_to "RSS", harvests_path(format: 'rss') - %li= link_to "CSV", harvests_path(format: 'csv') - %li= link_to "JSON", harvests_path(format: 'json') +%section.open-data + %h5= t('label.data') + %ul.nav#open-data + - ['csv', 'json', 'rss'].each do |format| + %li.list-group-item + = link_to (@owner ? member_harvests_path(@owner, format: format) : harvests_path(format: format)) do + = icon 'fas', format.to_s + = format.upcase \ No newline at end of file diff --git a/app/views/harvests/show.html.haml b/app/views/harvests/show.html.haml index 116a7ec84..cc68a79bd 100644 --- a/app/views/harvests/show.html.haml +++ b/app/views/harvests/show.html.haml @@ -8,46 +8,48 @@ = tag("meta", property: "og:url", content: request.original_url) = tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME']) +- content_for :breadcrumbs do + %li.breadcrumb-item= link_to 'Harvests', harvests_path + %li.breadcrumb-item= link_to @harvest.owner, member_harvests_path(@harvest.owner) + %li.breadcrumb-item.active= link_to @harvest, @harvest + .row .col-md-8 %h1 = harvest_icon #{@harvest.crop} harvested by #{@harvest.owner} = render 'harvests/actions', harvest: @harvest - = link_to "view all #{@harvest.owner}'s harvests >>", member_harvests_path(@harvest.owner), class: 'btn' - .index-cards.planting-facts + = render partial: 'planting' + .index-cards.facts - if @harvest.plant_part - .card.planting-fact-card + .card %h3 Plant part %span= link_to @harvest.plant_part, @harvest.plant_part - if @harvest.harvested_at.present? - .card.planting-fact-card + .card %h3 Harvested - = @harvest.harvested_at - - .card.planting-fact-card - %h3 Planting - = render partial: 'planting' - .card.planting-fact-card + %strong= I18n.l @harvest.harvested_at + .card %h3 Quantity - %span= display_quantity(@harvest) - - - .col-md-4 - .card - .card-body= render 'harvests/owner', harvest: @harvest - - = render @harvest.crop - - %hr/ + %strong= display_quantity(@harvest) - if @harvest.photos.size.positive? - .row - .col-md-6= render @harvest.default_photo - .col-md-6 - = render 'photos/gallery', photos: @harvest.photos.order(date_taken: :desc).limit(3).offset(1) - %p.text-right= link_to 'View all photos >>', harvest_photos_path(@harvest), class: 'btn' - .col-md-4 - .card - .card-body= render 'harvests/owner', harvest: @harvest + %section + %h2 Photos + = render 'photos/gallery', photos: @harvest.photos.order(date_taken: :desc).limit(3) + %section.harvest-detail + %h2 Detail + - if @harvest.planting.present? + Havested from + = link_to @harvest.planting, @harvest.planting - = render @harvest.crop \ No newline at end of file + - if @harvest.description.present? + .card + .card-header + %h2 Notes + .card-body + :growstuff_markdown + #{strip_tags(@harvest.description)} + + .col-md-4 + = render 'harvests/owner', harvest: @harvest + = render @harvest.crop diff --git a/app/views/home/_blurb.html.haml b/app/views/home/_blurb.html.haml index 9c942acad..11582e8b6 100644 --- a/app/views/home/_blurb.html.haml +++ b/app/views/home/_blurb.html.haml @@ -1,6 +1,6 @@ .row .col-md-8.info - %h1= ENV['GROWSTUFF_SITE_NAME'] + %h1.display-1= ENV['GROWSTUFF_SITE_NAME'] %p= t('.intro', site_name: ENV['GROWSTUFF_SITE_NAME']) = render 'stats' .col-md-4 diff --git a/app/views/home/_crops.html.haml b/app/views/home/_crops.html.haml index 974abdb63..9a6d9d658 100644 --- a/app/views/home/_crops.html.haml +++ b/app/views/home/_crops.html.haml @@ -1,6 +1,5 @@ - cache cache_key_for(Crop, 'homepage'), expires_in: 1.day do - .row + .index-cards - Crop.interesting.includes(:scientific_names, :photos).shuffle.first(12).each do |crop| - .col-6.col-md-3 - = render 'crops/thumbnail', crop: crop + = render 'crops/thumbnail', crop: crop diff --git a/app/views/home/_harvests.html.haml b/app/views/home/_harvests.html.haml index aab9c71d4..05948de40 100644 --- a/app/views/home/_harvests.html.haml +++ b/app/views/home/_harvests.html.haml @@ -1,12 +1,10 @@ -%section.harvests - %h5= t('.recently_harvested') - - Harvest.has_photos.recent.includes(:crop, :owner, :photos).limit(6).each do |harvest| - .card - = link_to harvest, class: 'list-group-item list-group-item-action flex-column align-items-start' do - .d-flex.w-100.justify-content-between - %div - %h5.mb-2.h5= harvest.crop.name - %span.badge.badge-success=harvest.plant_part - %small.text-muted - harvested by #{harvest.owner} - %p.mb-2= image_tag harvest_image_path(harvest), width: 75, class: 'rounded shadow' \ No newline at end of file +%h2= t('.recently_harvested') +- Harvest.has_photos.recent.includes(:crop, :owner, :photos).limit(6).each do |harvest| + = link_to harvest, class: 'list-group-item list-group-item-action flex-column align-items-start' do + .d-flex.w-100.justify-content-between.homepage--list-item + %div + %h5= harvest.crop.name + %span.badge.badge-success=harvest.plant_part + %small.text-muted + harvested by #{harvest.owner} + %p.mb-2= image_tag harvest_image_path(harvest), width: 75, class: 'rounded shadow' \ No newline at end of file diff --git a/app/views/home/_members.html.haml b/app/views/home/_members.html.haml index 90d4c7078..1dcb960b2 100644 --- a/app/views/home/_members.html.haml +++ b/app/views/home/_members.html.haml @@ -3,7 +3,7 @@ - members = Member.includes(plantings: :crop).interesting.limit(6) - if members.present? %h2.text-center= t('.title') - .member-cards.index-cards + .index-cards = render members %p.text-right diff --git a/app/views/home/_plantings.html.haml b/app/views/home/_plantings.html.haml index c06951ada..a148a05fe 100644 --- a/app/views/home/_plantings.html.haml +++ b/app/views/home/_plantings.html.haml @@ -1,13 +1,12 @@ -%section.plantings - %h5= t('.recently_planted') +%h2= t('.recently_planted') - - Planting.has_photos.recent.includes(:crop, garden: :owner).limit(6).each do |planting| - .card.planting-card - = link_to planting, class: 'list-group-item list-group-item-action flex-column align-items-start' do - .d-flex.w-100.justify-content-between - %p.mb-2= image_tag planting_image_path(planting), width: 75, class: 'rounded shadow' - .text-right - %h5.mb-2.h5= planting.crop.name - - if planting.planted_from.present? - %span.badge.badge-success= planting.planted_from.pluralize - %small.text-muted= display_planting(planting) \ No newline at end of file +- Planting.has_photos.recent.includes(:crop, garden: :owner).limit(6).each do |planting| + = link_to planting, class: 'list-group-item list-group-item-action flex-column align-items-start' do + .d-flex.w-100.justify-content-between.homepage--list-item + %p.mb-2 + = image_tag planting_image_path(planting), width: 75, class: 'rounded shadow' + .text-right + %h5= planting.crop.name + - if planting.planted_from.present? + %span.badge.badge-success= planting.planted_from.pluralize + %small.text-muted planted by #{planting.owner} \ No newline at end of file diff --git a/app/views/home/_seeds.html.haml b/app/views/home/_seeds.html.haml index bff02e70d..38ae29fd9 100644 --- a/app/views/home/_seeds.html.haml +++ b/app/views/home/_seeds.html.haml @@ -1,5 +1,5 @@ - cache cache_key_for(Seed) do %h2.text-center= t('home.seeds.title') - .homepage-cards + .index-cards - Seed.current.tradable.includes(:owner, :crop).order(created_at: :desc).limit(6).each do |seed| = render 'seeds/card', seed: seed diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index dd748925f..3b027c956 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -2,35 +2,38 @@ = ENV['GROWSTUFF_SITE_NAME'] - if member_signed_in? - %h1.display-5= t('.welcome', site_name: ENV['GROWSTUFF_SITE_NAME'], member_name: current_member) + %h1.display-2= t('.welcome', site_name: ENV['GROWSTUFF_SITE_NAME'], member_name: current_member) %p= render 'stats' - else .hidden-xs - .jumbotron= render 'blurb' + %section.jumbotron= render 'blurb' .row - .col-xl-8.col-md-12 + .col-lg-8.col-md-12 %section.crops %h2= t('home.crops.our_crops') - .homepage-cards= render 'crops' - .align-bottom - %p.text-right= link_to "#{t('home.crops.view_all')} »", crops_path, class: 'btn btn-block' - - cache cache_key_for(Crop, 'recent') do - %h3= t('.recently_added') + = render 'crops' + = link_to "#{t('home.crops.view_all')} »", crops_path, class: 'btn btn-block' + %section.recent-crops + - cache cache_key_for(Crop, 'recent') do + %h2= t('.recently_added') + %p != Crop.recent.limit(30).map { |c| link_to(c, c) }.join(", ") - .col-xl-4 - .row - .col-md-6 - =render 'plantings' - %p.text-right= link_to "#{t('home.plantings.view_all')} »", plantings_path, class: 'btn btn-block' - .col-md-6 - = render 'harvests' - %p.text-right= link_to "#{t('home.harvests.view_all')} »", harvests_path, class: 'btn btn-block' - .col-md-6 - %section.seeds.mx-auto + + .col-xl-2.col + %section.plantings + =render 'plantings' + %p.text-right= link_to "#{t('home.plantings.view_all')} »", plantings_path, class: 'btn btn-block' + .col-xl-2.col + %section.harvests + = render 'harvests' + %p.text-right= link_to "#{t('home.harvests.view_all')} »", harvests_path, class: 'btn btn-block' + .col-12.col-md-6 + %section.seeds = render 'seeds' %p.text-right= link_to "#{t('home.seeds.view_all')} »", seeds_path, class: 'btn btn-block' - .col-md-6 - %section.members.mx-auto= render 'members' - %section.discussion.mx-auto= render 'discuss' \ No newline at end of file + .col-12.col-md-6 + %section.discussion= render 'discuss' + .col-12 + %section.members= render 'members' diff --git a/app/views/layouts/_fact_card.haml b/app/views/layouts/_fact_card.haml new file mode 100644 index 000000000..daaa36468 --- /dev/null +++ b/app/views/layouts/_fact_card.haml @@ -0,0 +1,6 @@ +.card.fact-card + .card-body.text-center + %h3= title + %strong= value + - if description.present? + %span= description \ No newline at end of file diff --git a/app/views/layouts/_nav.haml b/app/views/layouts/_nav.haml index 6af1aaa10..07477f19a 100644 --- a/app/views/layouts/_nav.haml +++ b/app/views/layouts/_nav.haml @@ -1,14 +1,17 @@ -- content_for :buttonbar do +%ul.nav - if current_member.present? - = link_to url_for([current_member, model]), class: 'btn' do - My #{model.model_name.human.pluralize} + %li.list-group-item.btn + = link_to url_for([current_member, model]) do + My #{model.model_name.human.pluralize} - = link_to model, class: 'btn' do - Everyone's #{model.model_name.human.pluralize} + %li.list-group-item.btn + = link_to model do + Everyone's #{model.model_name.human.pluralize} - if can?(:create, model) - = link_to url_for([model, action: :new]), class: 'btn' do - Add a #{model.model_name.human} + %li.list-group-item.btn + = link_to url_for([model, action: :new]) do + Add a #{model.model_name.human} - unless current_member = render 'shared/signin_signup', to: "add a new #{model.to_s.downcase}" diff --git a/app/views/layouts/_pagination.html.haml b/app/views/layouts/_pagination.html.haml index 186c6b32e..a57470a4b 100644 --- a/app/views/layouts/_pagination.html.haml +++ b/app/views/layouts/_pagination.html.haml @@ -1 +1 @@ -= will_paginate collection, renderer: WillPaginate::ActionView::BootstrapLinkRenderer \ No newline at end of file += will_paginate collection \ No newline at end of file diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 0cfbdd58e..a378fc735 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -7,10 +7,10 @@ = render "layouts/header" -# anchor tag for accessibility link to skip the navigation menu %a{ name: 'skipnav' } - #maincontainer.container + #maincontainer.container-fluid .row .col-12 - .float-right= render 'shared/global_actions' + .layout-actions= render 'shared/global_actions' - if content_for?(:breadcrumbs) .float-left %nav{"aria-label" => "breadcrumb"} @@ -19,7 +19,7 @@ = yield(:breadcrumbs) - if content_for?(:buttonbar) - .layout-actions.float-right= yield(:buttonbar) + = yield(:buttonbar) - if content_for?(:subtitle) %small= yield(:subtitle) diff --git a/app/views/members/_location.html.haml b/app/views/members/_location.html.haml index 3b9a2f647..7c08e6acb 100644 --- a/app/views/members/_location.html.haml +++ b/app/views/members/_location.html.haml @@ -1,6 +1,8 @@ -%span.badge.badge-light.member-location - - if member.location.blank? - unknown location - - else - = link_to place_path(member.location, anchor: "members") do - = truncate(member.location, length: 40, separator: ' ', omission: '... ') +- if member.location.present? + = link_to place_path(member.location) do + %span.badge.badge-location + = icon 'fas', 'map-marker' + = truncate(member.location, length: 15, separator: ' ', omission: '... ') +- else + %span.badge.badge-location + unknown location \ No newline at end of file diff --git a/app/views/members/_member.haml b/app/views/members/_member.haml index 2274a8e5c..7c10ce280 100644 --- a/app/views/members/_member.haml +++ b/app/views/members/_member.haml @@ -11,9 +11,7 @@ = distance_of_time_in_words(member.created_at, Time.zone.now) ago. - if member.location.present? - %span.badge.badge-success - = icon 'fas', 'map-marker' - = truncate(member.location, length: 50, separator: ' ', omission: '... ') + = render 'members/location', member: member %p %ul.nav.nav-justified.small diff --git a/app/views/members/_tiny.haml b/app/views/members/_tiny.haml index dcd4e9987..4693bf373 100644 --- a/app/views/members/_tiny.haml +++ b/app/views/members/_tiny.haml @@ -1,4 +1,4 @@ -.member-chip +%span.member-chip - if member.discarded? = icon 'fas', 'user-times' = member diff --git a/app/views/members/nearby.html.haml b/app/views/members/nearby.html.haml index 2d9750c3e..57949ddec 100644 --- a/app/views/members/nearby.html.haml +++ b/app/views/members/nearby.html.haml @@ -17,9 +17,8 @@ - if !@nearby_members.empty? %h3 Results found - .row + .index-cards - @nearby_members.each do |member| - .col-md-4.three-across - = render partial: "members/thumbnail", locals: { member: member } + = render partial: "members/thumbnail", locals: { member: member } - elsif @location %h3 No results found diff --git a/app/views/members/show.html.haml b/app/views/members/show.html.haml index 5e1192c31..693a61d2a 100644 --- a/app/views/members/show.html.haml +++ b/app/views/members/show.html.haml @@ -20,9 +20,9 @@ - @member.roles.each do |role| %span.badge.badge-info= role.name.titleize - if @member.location.present? - %p.badge.badge-success + %p.badge.badge-location = icon 'fas', 'map-marker' - = @member.location + = truncate(@member.location, length: 25, separator: ' ', omission: '... ') %p %strong Member since = @member.created_at.to_s(:date) @@ -56,18 +56,19 @@ facebook_auth: @facebook_auth .col-md-10 - = render "map", member: @member - %h2 Activity - .list-group - - @activity.each do |event| - .list-group-item.list-group-item-action.flex-column.align-items-start{:href => "#!"} - .d-flex.w-100.justify-content-between - %h5 - = icon_for_model(event.event_type) - = event_description(event) - = render 'timeline/photos', photo: resolve_model(event) if event.event_type == 'photo' - %small - - if event.event_at.present? - #{time_ago_in_words(event.event_at)} ago - - else - unknown date + %section= render "map", member: @member + %section.activity + %h2 Activity + .list-group + - @activity.each do |event| + .list-group-item.list-group-item-action.flex-column.align-items-start{:href => "#!"} + .d-flex.w-100.justify-content-between + %h5 + = icon_for_model(event.event_type) + = event_description(event) + = render 'timeline/photos', photo: resolve_model(event) if event.event_type == 'photo' + %small + - if event.event_at.present? + #{time_ago_in_words(event.event_at)} ago + - else + unknown date diff --git a/app/views/photos/_card.html.haml b/app/views/photos/_card.html.haml index d16324610..f073cbef1 100644 --- a/app/views/photos/_card.html.haml +++ b/app/views/photos/_card.html.haml @@ -1,10 +1,11 @@ .card.photo-card{id: "photo-#{photo.id}"} = link_to image_tag(photo.source == 'flickr' ? photo.fullsize_url : photo.thumbnail_url, alt: photo.title, class: 'img img-card'), photo .card-body - %h5.ellipsis= link_to photo.title, photo + %h5.ellipsis + = photo_icon + = link_to photo.title, photo %i by #{link_to photo.owner, photo.owner} - if photo.date_taken.present? - %small - %time{datetime: photo.date_taken} - = I18n.l(photo.date_taken.to_date) + %small.text-muted + %time{datetime: photo.date_taken}= I18n.l(photo.date_taken.to_date) = render 'photos/likes', photo: photo diff --git a/app/views/photos/_gallery.haml b/app/views/photos/_gallery.haml index 98bed3450..e48872d81 100644 --- a/app/views/photos/_gallery.haml +++ b/app/views/photos/_gallery.haml @@ -1,4 +1,4 @@ .index-cards - photos.each do |photo| - .photo-grid-item= render 'photos/card', photo: photo + = render 'photos/card', photo: photo diff --git a/app/views/photos/_hero.html.haml b/app/views/photos/_hero.html.haml new file mode 100644 index 000000000..b269e4431 --- /dev/null +++ b/app/views/photos/_hero.html.haml @@ -0,0 +1,7 @@ +.photo.hero.jumbotron + .row + .col-6 + = image_tag(photo.fullsize_url, alt: photo.title, class: 'img img-responsive hero-photo') + .col-6 + %h3= link_to photo.title, photo + Taken on #{I18n.l photo.date_taken} diff --git a/app/views/photos/_item_photos.haml b/app/views/photos/_item_photos.haml deleted file mode 100644 index 05a2f8319..000000000 --- a/app/views/photos/_item_photos.haml +++ /dev/null @@ -1,11 +0,0 @@ -%h2 Photos - -- if photos.size.positive? || (can?(:edit, item) && can?(:create, Photo)) - - if photos.size.positive? - = page_entries_info photos - = will_paginate photos - .row - - photos.each do |photo| - .col-xs-6.col-md-3.six-across= render 'photos/thumbnail', photo: photo - -= add_photo_button(item) diff --git a/app/views/photos/_likes.html.haml b/app/views/photos/_likes.html.haml index 47cca8634..fb0b0e918 100644 --- a/app/views/photos/_likes.html.haml +++ b/app/views/photos/_likes.html.haml @@ -1,13 +1,14 @@ -- if member_signed_in? - - if can?(:new, Like) && !photo.liked_by?(current_member) - = link_to likes_path(photo_id: photo.id, format: :json), - method: :post, remote: true, class: 'photo-like like-btn' do - = render 'likes/count', likeable: photo - - else - - like = photo.likes.find_by(member: current_member) - - if like && can?(:destroy, like) - = link_to like_path(id: like.id, format: :json), - method: :delete, remote: true, class: 'photo-like like-btn' do +%span.likes + - if member_signed_in? + - if can?(:new, Like) && !photo.liked_by?(current_member) + = link_to likes_path(photo_id: photo.id, format: :json), + method: :post, remote: true, class: 'photo-like like-btn' do = render 'likes/count', likeable: photo -- else - = render 'likes/count', likeable: photo \ No newline at end of file + - else + - like = photo.likes.find_by(member: current_member) + - if like && can?(:destroy, like) + = link_to like_path(id: like.id, format: :json), + method: :delete, remote: true, class: 'photo-like like-btn' do + = render 'likes/count', likeable: photo + - else + = render 'likes/count', likeable: photo \ No newline at end of file diff --git a/app/views/photos/_photo.haml b/app/views/photos/_photo.haml index 341a8ec7f..bcd42f045 100644 --- a/app/views/photos/_photo.haml +++ b/app/views/photos/_photo.haml @@ -1,4 +1,4 @@ -.planting-full-photo +.photo = image_tag(photo.fullsize_url, alt: photo.title, class: 'img img-responsive') .text %p diff --git a/app/views/photos/index.html.haml b/app/views/photos/index.html.haml index 1f9896377..baef72745 100644 --- a/app/views/photos/index.html.haml +++ b/app/views/photos/index.html.haml @@ -8,21 +8,13 @@ - content_for :breadcrumbs do %li.breadcrumb-item= link_to 'Photos', photos_path -.pagination - = page_entries_info @photos - = will_paginate @photos -.row += page_entries_info @photos += will_paginate @photos + +.index-cards - @photos.each do |p| - .col-md-2.six-across - = render 'photos/card', photo: p - -# .thumbnail{ style: 'height: 220px' } - -# = link_to image_tag(p.thumbnail_url, alt: p.title, class: 'img'), p - -# %p - -# = link_to p.title, p - -# by - -# = link_to p.owner, p.owner + = render 'photos/card', photo: p -.pagination - = page_entries_info @photos - = will_paginate @photos += page_entries_info @photos += will_paginate @photos diff --git a/app/views/places/show.html.haml b/app/views/places/show.html.haml index 23fa46e3e..98b9b7360 100644 --- a/app/views/places/show.html.haml +++ b/app/views/places/show.html.haml @@ -9,46 +9,44 @@ %h1 #{ENV['GROWSTUFF_SITE_NAME']} community near #{@place} = render partial: 'search_form' -#placesmap{ style: "height:300px" } +%section.map#placesmap{ style: "height:300px" } -%h3#members= "Nearby members" +%section.members + %h2#members= "Nearby members" -- if !@nearby_members.empty? - .row - - @nearby_members.first(30).each do |member| - .col-md-4.three-across + - if @nearby_members.any? + .index-cards.members + - @nearby_members.first(30).each do |member| = render partial: "members/thumbnail", locals: { member: member } + - else + %p No nearby members = link_to "View all members >>", members_path - %h3#seeds Seeds available for trade near #{@place} +%section.seeds + %h2#seeds Seeds available for trade near #{@place} - crop_id = [] - @nearby_members.first(10).each do |member| - member.seeds.first(5).each do |seed| - crop_id.push seed.crop.id - - if !crop_id.blank? - .row + - if crop_id.present? + .index-cards.crops - crop_id.uniq.first(20).each do |crop| - .col-md-2.six-across - = render partial: "crops/thumbnail", locals: { crop: Crop.find(crop) } - = link_to "View all seeds >>", seeds_path + = render partial: "crops/thumbnail", locals: { crop: Crop.find(crop) } - else %p No nearby seeds found + = link_to "View all seeds >>", seeds_path - #plantings - %h3 Recent plantings near #{@place} - +%section#plantings + %h2 Recent plantings near #{@place} - plantings = [] - @nearby_members.first(10).each do |member| - member.plantings.first(5).each do |planting| - plantings << planting - - if !plantings.blank? - .row + - if plantings.any? + .index-cards.plantings - plantings.first(10).each.with_index do |planting, index| - .col-xs-12.col-lg-6 - = render partial: "plantings/card", locals: { planting: planting, index: index } - = link_to "View all plantings >>", plantings_path + = render partial: "plantings/card", locals: { planting: planting, index: index } - else %p No nearby plantings found -- else - %p No results found + = link_to "View all plantings >>", plantings_path diff --git a/app/views/plantings/_actions.html.haml b/app/views/plantings/_actions.html.haml index f69b900b9..e974526af 100644 --- a/app/views/plantings/_actions.html.haml +++ b/app/views/plantings/_actions.html.haml @@ -1,6 +1,6 @@ - if can?(:edit, planting) - .dropdown.float-right.planting-actions - %a#planting-actions-button.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", type: "button", href: '#'} Actions + .dropdown.planting-actions + %a#planting-actions-button.btn.btn-info.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", type: "button", href: '#'} Actions .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "planting-actions-button"} = planting_edit_button(planting, classes: 'dropdown-item') = add_photo_button(planting, classes: 'dropdown-item') diff --git a/app/views/plantings/_card.html.haml b/app/views/plantings/_card.html.haml index c6695f3e0..479815afa 100644 --- a/app/views/plantings/_card.html.haml +++ b/app/views/plantings/_card.html.haml @@ -1,6 +1,6 @@ -.card.planting +.card.planting-card.planting = link_to planting do - = image_tag planting_image_path(planting, full_size: true), class: 'img-card', alt: planting + = image_tag planting_image_path(planting), class: 'img-card', alt: planting - if can? :edit, planting .planting-quick-actions .dropdown @@ -21,4 +21,6 @@ .card-body.text-center %h4.card-title= link_to planting.crop, planting .text-center= render 'plantings/badges', planting: planting - = render 'plantings/progress', planting: planting \ No newline at end of file + = render 'plantings/progress', planting: planting + -# .card-footer + -# .float-right=render 'members/tiny', member: planting.owner \ No newline at end of file diff --git a/app/views/plantings/_descendants.html.haml b/app/views/plantings/_descendants.html.haml index 4cfc1e23e..64f93a2c8 100644 --- a/app/views/plantings/_descendants.html.haml +++ b/app/views/plantings/_descendants.html.haml @@ -1,8 +1,8 @@ %h2 Seeds saved - - if planting.child_seeds.size.positive? - - planting.child_seeds.each do |seed| - = render 'seeds/thumbnail', seed: seed + .index-cards + - planting.child_seeds.each do |seed| + = render 'seeds/card', seed: seed - else %p No seeds saved diff --git a/app/views/plantings/_facts.haml b/app/views/plantings/_facts.haml index 480595bde..a6afb8122 100644 --- a/app/views/plantings/_facts.haml +++ b/app/views/plantings/_facts.haml @@ -1,106 +1,88 @@ -.index-cards.planting-facts +.index-cards.facts.plantingfacts - if planting.parent_seed - .card.planting-fact-card + .card.fact-card %h3 Parent seed - %strong + %strong.plantingfact--parentseed = link_to seed_path(planting.parent_seed) do = seed_icon %span=planting.parent_seed - - - if planting.finished - .card.planting-fact-card + - if planting.finished? + .card.fact-card %h3 Planted %strong=planting_icon - if planting.quantity.present? - %span= planting.quantity + %span.plantingfact--quantity= planting.quantity - if planting.planted_at.present? && !planting.finished? - .card.planting-fact-card + .card.fact-card %h3 Planted - %strong #{planting.days_since_planted} + %strong.plantingfact--dayssinceplanted #{planting.days_since_planted} %span days ago - if planting.quantity.to_i.positive? - .card.planting-fact-card + .card.fact-card %h3 Quantity - %strong= planting.quantity + %strong.plantingfact--quantity= planting.quantity %span - if planting.planted_from.present? #{pluralize((planting.quantity.to_i), planting.planted_from)} - unless planting.finished? - .card.planting-fact-card.grid-sizer + .card.fact-card.grid-sizer %h3 Growing %strong= seedling_icon - if planting.planted_at.present? - %span= planting.planted_at.to_formatted_s(:rfc822) - - - if planting.percentage_grown - .card.planting-fact-card - %h3 Progress - %strong #{sprintf '%.0f', planting.percentage_grown}% - .progress - .progress-bar.progress-bar-success{"aria-valuemax" => "100", "aria-valuemin" => "0", "aria-valuenow" => planting.percentage_grown, :role => "progressbar", :style => "width: #{planting.percentage_grown}%"} - %span.sr-only #{sprintf '%.0f', planting.percentage_grown}% - - + %span.plantingfact--planttedat= I18n.l planting.planted_at.to_date - if planting.planted_from.present? - .card.planting-fact-card + .card.fact-card %h3 Grown from - %span=planting.planted_from + %span.plantingfact--plantedfrom=planting.planted_from - .card.planting-fact-card + .card.fact-card %h3 Grown in %strong= sunniness_icon(planting.sunniness) - %span= planting.sunniness.blank? ? "not specified" : planting.sunniness + %span.plantingfact--sunniness= planting.sunniness.blank? ? "not specified" : planting.sunniness - -# .card.planting-fact-card - -# %h3 Garden - -# = link_to planting.garden do - -# - if planting.garden.default_photo.present? - -# = image_tag planting.garden.default_photo.thumbnail_url - -# - else - -# %strong= garden_icon - -# %span= planting.garden.name - - .card.planting-fact-card - %h3 - = planting.finished? ? "Harvests" : "Harvesting" + .card.fact-card + %h3.plantingfact--harveststitle + = planting.finished? ? "Harvested" : "Harvesting" %strong = link_to planting_harvests_path(planting) do = harvest_icon - %span= planting.first_harvest_date&.to_formatted_s(:rfc822) || planting&.first_harvest_predicted_at&.to_formatted_s(:rfc822) || 'unknown' + %span.plantingfact--harvestprediction + = planting.first_harvest_date&.to_formatted_s(:rfc822) || planting&.first_harvest_predicted_at&.to_formatted_s(:rfc822) || 'unknown' - if planting.crop.perennial - .card.planting-fact-card - %h3 Perennial + .card.fact-card + %h3.plantingfact--perennial Perennial %strong=perennial_icon - else - if !planting.finished? && planting.finish_is_predicatable? - .card.planting-fact-card + .card.fact-card - days = days_from_now_to_finished(planting) - if days.positive? - %h3 Prediction - %strong #{days} + %h3.plantingfact--finishtitle Prediction + %strong.plantingfact--finisheddays #{days} %span days until finished - else - %h3 Finish - %strong #{days * -1} + %h3.plantingfact--finishtitle Finished + %strong.plantingfact--finisheddays #{days * -1} %span days ago %span= planting.finish_predicted_at&.to_formatted_s(:rfc822) - if planting.child_seeds.size.positive? - .card.planting-fact-card + .card.fact-card %h3 Seeds saved %strong = link_to planting_seeds_path(planting) do = seed_icon - %span #{pluralize(planting.child_seeds.size, 'packet')} of seed + %span.plantingfact--seedssaved #{pluralize(planting.child_seeds.size, 'packet')} of seed - if planting.finished? - .card.planting-fact-card + .card.fact-card %h3 Finished %strong=finished_icon - %span=planting.finished_at&.to_formatted_s(:rfc822) + %span.plantingfact--finish=planting.finished_at&.to_formatted_s(:rfc822) + diff --git a/app/views/plantings/_harvests.html.haml b/app/views/plantings/_harvests.html.haml index 5ed44f59f..ec3933ef1 100644 --- a/app/views/plantings/_harvests.html.haml +++ b/app/views/plantings/_harvests.html.haml @@ -4,8 +4,8 @@ - if !planting.finished? && can?(:edit, planting) && can?(:create, Harvest) %p Record your harvests here to improve crop predictions, and you'll be able to compare with your garden next season. - else - .row + .index-cards - planting.harvests.order(created_at: :desc).includes(:crop).each do |harvest| - .col-md-2.col-sm-6= render 'harvests/thumbnail', harvest: harvest + = render 'harvests/card', harvest: harvest = planting_harvest_button(planting) diff --git a/app/views/plantings/_owner.haml b/app/views/plantings/_owner.haml index b1a57a937..a97625dec 100644 --- a/app/views/plantings/_owner.haml +++ b/app/views/plantings/_owner.haml @@ -1,17 +1,18 @@ -.well - .row - .col-md-6 - %h4 - Planted by - = link_to @planting.owner, @planting.owner - = link_to "view all #{@planting.owner}'s plantings", member_gardens_path(@planting.owner) +.card + .card-body + .row + .col-md-6 + %h4 + Planted by + = link_to @planting.owner, @planting.owner + = link_to "view all #{@planting.owner}'s plantings", member_gardens_path(@planting.owner) - %p - Planted in - = link_to @planting.garden, @planting.garden - - 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") - .col-md-6= render "members/avatar", member: @planting.owner \ No newline at end of file + Planted in + = link_to @planting.garden, @planting.garden + - 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") + .col-md-6= render "members/avatar", member: @planting.owner \ No newline at end of file diff --git a/app/views/plantings/_progress.html.haml b/app/views/plantings/_progress.html.haml index 16fb5686f..a26fa646a 100644 --- a/app/views/plantings/_progress.html.haml +++ b/app/views/plantings/_progress.html.haml @@ -4,5 +4,5 @@ .float-left #{sprintf '%.0f', planting.percentage_grown}% -- unless planting.finish_predicted_at.blank? - .float-right= planting.finish_predicted_at.strftime(Date::DATE_FORMATS[:ymd]) + - unless planting.finish_predicted_at.blank? + .float-right= planting.finish_predicted_at.strftime(Date::DATE_FORMATS[:ymd]) diff --git a/app/views/plantings/_thumbnail.html.haml b/app/views/plantings/_thumbnail.html.haml index c8513fd7e..aec971fd3 100644 --- a/app/views/plantings/_thumbnail.html.haml +++ b/app/views/plantings/_thumbnail.html.haml @@ -1,10 +1,12 @@ .card.thumbnail /= render 'plantings/quick_actions', planting: planting .planting-thumbnail-image - = link_to image_tag(planting_image_path(planting, full_size: true), + = link_to image_tag(planting_image_path(planting), alt: planting.crop, class: 'img-card'), planting .card-body - %h5.card-title= link_to planting.crop, planting + %h5.card-title + = crop_icon(planting.crop) + = link_to planting.crop, planting %h6.card-subtitle.text-muted=planting.finished_at = render 'plantings/badges', planting: planting diff --git a/app/views/plantings/index.html.haml b/app/views/plantings/index.html.haml index f0c60a53e..407a97b41 100644 --- a/app/views/plantings/index.html.haml +++ b/app/views/plantings/index.html.haml @@ -1,11 +1,5 @@ - content_for :title, title('plantings', @owner, @crop, @planting) -%h1 - = planting_icon - = title('plantings', @owner, @crop, @planting) - -= render 'layouts/nav', model: Planting - - content_for :breadcrumbs do - if @owner %li.breadcrumb-item= link_to 'Plantings', plantings_path @@ -13,6 +7,13 @@ - else %li.breadcrumb-item.active= link_to 'Plantings', plantings_path +%h1 + = planting_icon + = title('plantings', @owner, @crop, @planting) + += render 'layouts/nav', model: Planting + + %section.border-top .btn-group = link_to plantings_active_tickbox_path(@owner, @show_all), class: 'btn' do @@ -26,15 +27,19 @@ .col-12= page_entries_info @plantings .col-12= render 'layouts/pagination', collection: @plantings -.index-cards= render @plantings, full: true +.index-cards + - @plantings.each do |planting| + = render planting, full: true .row .col-12= page_entries_info @plantings .col-12= render 'layouts/pagination', collection: @plantings -%p= t('.the_data_on_this_page_is_available_in_the_following_formats') -%ul.list-group.list-group-horizontal - - ['csv', 'json', 'rss'].each do |format| - %li.list-group-item - = icon 'fas', format - = link_to format.upcase, (@owner ? member_plantings_path(@owner, format: format) : plantings_path(format: format)) +%section.open-data + %h5= t('label.data') + %ul.nav#open-data + - ['csv', 'json', 'rss'].each do |format| + %li.list-group-item + = link_to (@owner ? member_plantings_path(@owner, format: format) : plantings_path(format: format)) do + = icon 'fas', format.to_s + = format.upcase diff --git a/app/views/plantings/show.html.haml b/app/views/plantings/show.html.haml index 160c7d031..f173b2ba4 100644 --- a/app/views/plantings/show.html.haml +++ b/app/views/plantings/show.html.haml @@ -9,16 +9,22 @@ = tag("meta", property: "og:url", content: request.original_url) = tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME']) +- content_for :breadcrumbs do + %li.breadcrumb-item= link_to 'Plantings', plantings_path + %li.breadcrumb-item= link_to @planting.owner, member_plantings_path(@planting.owner) + %li.breadcrumb-item.active= link_to @planting, @planting .planting .row .col-md-8.col-xs-12 - %h1 - = planting_icon - %strong= @planting - = render 'plantings/actions', planting: @planting + %h1.plantingtitle + %span.plantingtitle--icon= planting_icon + = @planting.to_s.titleize + + = render 'plantings/actions', planting: @planting %section= render 'facts', planting: @planting + - if @planting.description.present? %hr/ .card @@ -27,15 +33,19 @@ .card-body :growstuff_markdown #{strip_tags(@planting.description)} - %hr/ %section= render 'plantings/photos', photos: @photos, planting: @planting - .col-md-4.col-xs-12.text-right - .card - .card-body= render 'plantings/owner', planting: @planting + .col-md-4.col-xs-12 + - if @planting.percentage_grown + .card + .progress + .progress-bar{"aria-valuemax" => "100", "aria-valuemin" => "0", "aria-valuenow" => @planting.percentage_grown, role: "progressbar", style: "width: #{@planting.percentage_grown}%"} + %strong.plantingfact--percentagegrown + #{sprintf '%.0f', @planting.percentage_grown}% + + = render 'plantings/owner', planting: @planting = render @planting.crop .row - .col-md-12 - %hr/ + .col-md-6 %section= render 'plantings/harvests', planting: @planting - %hr/ + .col-md-6 %section= render 'plantings/descendants', planting: @planting diff --git a/app/views/posts/_preview.haml b/app/views/posts/_preview.haml index 1d7ccbf37..275e5f1fa 100644 --- a/app/views/posts/_preview.haml +++ b/app/views/posts/_preview.haml @@ -1,14 +1,6 @@ -%section - .row - .col-md-12 - .card.card-cascade - .card-header - %h2= link_to post.subject, post - %p - Written by - %strong= link_to post.author, post.author - .card-body - .float-right= render 'members/tiny', member: post.author - - %p - = truncate(strip_tags(post.body), length: 200) +.card.card-cascade + .card-header + %h3= link_to post.subject, post + = render 'members/tiny', member: post.author + .card-body + %p= truncate(strip_tags(post.body), length: 200) diff --git a/app/views/posts/index.html.haml b/app/views/posts/index.html.haml index fd987aeac..9e1ffc35b 100644 --- a/app/views/posts/index.html.haml +++ b/app/views/posts/index.html.haml @@ -1,47 +1,47 @@ - content_for :title, @author ? t('.title.author_posts', author: @author) : t('.title.default') - content_for :breadcrumbs do + %li.breadcrumb-item= link_to 'Posts', posts_path - if @author.present? %li.breadcrumb-item= link_to @author, @author %li.breadcrumb-item.active= link_to 'posts', posts_path(author: @author.slug) %h1= @author ? t('.title.author_posts', author: @author) : t('.title.default') -.pagination= render 'layouts/pagination', collection: @posts -.row - .card-deck - - @posts.each do |post| - .col-12.col-md-6 - .card.post - .card-body - .row - .col-2.text-right - = render 'members/avatar', member: post.author - .col-10.border-left - %h5.card-title - = link_to strip_tags(post.subject), post - - if post.comments.size.positive? - %span.badge.badge-pill.badge-info.float-right - = icon 'fas', 'comment' - = post.comments.size - %p.text-muted - Posted by - - if post.author - = link_to post.author.login_name, member_path(post.author) - - else - Member Deleted - - if post.forum - in #{link_to post.forum, post.forum} - on #{post.created_at}" - - if post.updated_at > post.created_at - and edited at #{post.updated_at} - .card-text - .post-body= display_post_truncated(post) - - post.crops.each do |crop| - %span.badge.badge-pill.badge-primary= link_to crop, crop += render 'layouts/nav', model: Post + += will_paginate @posts + +- @posts.each do |post| + .card.post + .card-body + %h5.card-title + = link_to strip_tags(post.subject), post + - if post.comments.size.positive? + %span.badge.badge-pill.badge-info.float-right + = icon 'fas', 'comment' +   + = post.comments.size + %p.text-muted + Posted by + - if post.author + = link_to post.author.login_name, member_path(post.author) + - else + Member Deleted + + - if post.forum + in #{link_to post.forum, post.forum} + on #{post.created_at}" + - if post.updated_at > post.created_at + and edited at #{post.updated_at} + = render 'members/tiny', member: post.author + .card-body + .post-body= display_post_truncated(post) + - post.crops.each do |crop| + = render 'crops/tiny', crop: crop -.pagination= render 'layouts/pagination', collection: @posts += will_paginate @posts %p - if @author diff --git a/app/views/posts/show.html.haml b/app/views/posts/show.html.haml index f88612496..f7d09a620 100644 --- a/app/views/posts/show.html.haml +++ b/app/views/posts/show.html.haml @@ -51,16 +51,17 @@ = icon 'fas', 'comment' Comment - %secion.comments= render "comments", post: @post + %section.comments + = render "comments", post: @post .col-md-4.col-12 = render @post.author - .row - - unless @post.crops.empty? - .col-12 - %h3.h3 Crops mentioned in this post - - @post.crops.each do |c| - .col-6= render 'crops/thumbnail', crop: c + - unless @post.crops.empty? + %section.crops + %h2 Crops mentioned in this post + .index-cards + - @post.crops.each do |c| + = render 'crops/thumbnail', crop: c diff --git a/app/views/seeds/_actions.html.haml b/app/views/seeds/_actions.html.haml index 716724399..5cc91951a 100644 --- a/app/views/seeds/_actions.html.haml +++ b/app/views/seeds/_actions.html.haml @@ -1,12 +1,12 @@ -- if can?(:create, Planting) && can?(:update, seed) && seed.active? - = link_to new_planting_path(seed_id: seed), class: 'btn btn-info' do - %span.glyphicon.glyphicon-grain{ title: "Plant seeds" } - Plant seeds - if can?(:edit, seed) - .dropdown.float-right.seed-actions - %a#seed-actions-button.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", type: "button", href: '#'} + .dropdown.seed-actions + %a#seed-actions-button.btn.btn-info.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", type: "button", href: '#'} Actions .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "seed-actions-button"} + - if can?(:create, Planting) && can?(:update, seed) && seed.active? + = link_to new_planting_path(seed_id: seed), class: 'dropdown-item success-color' do + = seed_icon + Plant seeds = seed_edit_button(seed, classes: 'dropdown-item') = add_photo_button(seed, classes: 'dropdown-item') - if seed.active? diff --git a/app/views/seeds/_card.html.haml b/app/views/seeds/_card.html.haml index cd7db9099..a6a975ef2 100644 --- a/app/views/seeds/_card.html.haml +++ b/app/views/seeds/_card.html.haml @@ -1,13 +1,16 @@ .card.seed-card = link_to seed do - = image_tag(seed_image_path(seed, full_size: true), alt: seed, class: 'img-card') + = image_tag(seed_image_path(seed), alt: seed, class: 'img-card') .card-body - .card-title= link_to seed.crop, seed + .card-title + = crop_icon(seed.crop) + = link_to seed.crop, seed .card-footer = render 'members/tiny', member: seed.owner - if seed.tradable? - %span.badge.badge-pill.badge-info + .text-muted = icon 'fas', 'map' Will trade #{seed.tradable_to} - %span.badge.badge-pill.badge-secondary - = truncate(seed.owner.location, length: 30, separator: ' ', omission: '... ') \ No newline at end of file + .badge.badge-pill.badge-location + = icon 'fas', 'map-marker' + = truncate(seed.owner.location, length: 20, separator: ' ', omission: '... ') \ No newline at end of file diff --git a/app/views/seeds/_descendants.html.haml b/app/views/seeds/_descendants.html.haml index 1736d0bca..3a2a445aa 100644 --- a/app/views/seeds/_descendants.html.haml +++ b/app/views/seeds/_descendants.html.haml @@ -1,13 +1,5 @@ -%h2 Plants grown from these seeds -- if @seed.child_plantings - .row +- if @seed.child_plantings.any? + %h2 Plants grown from these seeds + .index-cards - 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 + = render 'plantings/thumbnail', planting: planting diff --git a/app/views/seeds/_facts.html.haml b/app/views/seeds/_facts.html.haml new file mode 100644 index 000000000..51e19212c --- /dev/null +++ b/app/views/seeds/_facts.html.haml @@ -0,0 +1,29 @@ +.index-cards.facts.seedfacts + .card + %h3 Quantity + %strong.seedfacts--quantity= seed.quantity.blank? ? "not specified" : seed.quantity + %span seeds + + - if seed.plant_before.present? + .card.seedfacts--card + %h3 Plant before + %strong.seedfacts--plantbefore= I18n.l(seed.plant_before) + + -if seed.finished_at.present? + .card + %h3 Finished at + %strong.seedfacts--finishedat= I18n.l(seed.finished_at) + .card + %h3 Days until maturity + %strong.seedfacts--maturity= render partial: 'days_until_maturity', locals: { seed: seed } + + .card + %h3 Will trade + %strong.seedfacts--tradableto= seed.tradable_to + %span + - 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 #{link_to seed.owner.location, place_path(seed.owner.location, anchor: "seeds")}) diff --git a/app/views/seeds/_owner.html.haml b/app/views/seeds/_owner.html.haml new file mode 100644 index 000000000..0dd3f9dda --- /dev/null +++ b/app/views/seeds/_owner.html.haml @@ -0,0 +1,19 @@ +.card + .card-body + .row + .col-md-6 + %h4 + Planted by + = link_to @seed.owner, @seed.owner + = link_to "view all #{@seed.owner}'s seeds", member_seeds_path(@seed.owner) + + - if @seed.parent_planting.present? + %p + Collected from + = link_to @seed.parent_planting, @seed.parent_planting + - if @seed.owner.location + %p + %small + View other seeds, members and more near + = link_to @seed.owner.location, place_path(@seed.owner.location, anchor: "seeds") + .col-md-6= render "members/avatar", member: @seed.owner \ No newline at end of file diff --git a/app/views/seeds/index.html.haml b/app/views/seeds/index.html.haml index 2b366b8c1..103fe7292 100644 --- a/app/views/seeds/index.html.haml +++ b/app/views/seeds/index.html.haml @@ -30,21 +30,12 @@ = page_entries_info @seeds = will_paginate @seeds - %ul.nav.justify-content-center - %li.nav-item - The data on this page is available in the following formats: - - if @owner - %li.nav-item - = link_to "CSV", member_seeds_path(@owner, format: 'csv'), class: 'nav-link' - %li.nav-item - = link_to "JSON", member_seeds_path(@owner, format: 'json'), class: 'nav-link' - %li.nav-item - = link_to "RSS", member_seeds_path(@owner, format: 'rss'), class: 'nav-link' - - else - %li.nav-item - = link_to "CSV", seeds_path(format: 'csv'), class: 'nav-link' - %li.nav-item - = link_to "JSON", seeds_path(format: 'json'), class: 'nav-link' - %li.nav-item - = link_to "RSS", seeds_path(format: 'rss'), class: 'nav-link' +%section.open-data + %h5= t('label.data') + %ul.nav#open-data + - ['csv', 'json', 'rss'].each do |format| + %li.list-group-item + = link_to (@owner ? member_seeds_path(@owner, format: format) : seeds_path(format: format)) do + = icon 'fas', format.to_s + = format.upcase diff --git a/app/views/seeds/show.html.haml b/app/views/seeds/show.html.haml index 07aec7b53..7ada4e8d9 100644 --- a/app/views/seeds/show.html.haml +++ b/app/views/seeds/show.html.haml @@ -12,58 +12,39 @@ - content_for :breadcrumbs do %li.breadcrumb-item= link_to 'Seeds', seeds_path + %li.breadcrumb-item= link_to @seed.owner, member_seeds_path(@seed.owner) %li.breadcrumb-item.active= link_to @seed, @seed -.row - .col-md-6 +.row.seeds + .col-md-8 %h1 - #{@seed.owner}'s #{@seed.crop} seeds - = render 'seeds/actions', seed: @seed - %dl.dl-horizontal - %dt Owner - %dd - = link_to @seed.owner, @seed.owner - — - = link_to "view all #{@seed.owner}'s seeds", - member_seeds_path(@seed.owner) - %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") + %span.seedtitle--icon= crop_icon(@seed.crop) + %strong + %span.seedtitle--owner #{@seed.owner}'s + %span.seedtitle--crop #{@seed.crop} + seeds + - if @seed.organic != 'unknown' + %small.seedtitle--organic= @seed.organic + - if @seed.gmo != 'unknown' + %small.seedtitle--gmo= @seed.gmo + - if @seed.heirloom != 'unknown' + %small.seedtitle--heirloom= @seed.heirloom + = I18n.l @seed.created_at.to_date - %dt When? + = render 'seeds/actions', seed: @seed + + %section= render 'facts', seed: @seed + - if @seed.parent_planting + %dt Saved from planting: %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." } + = link_to @seed.parent_planting, planting_path(@seed.parent_planting) + - unless @seed.description.blank? + .card.seed--description + .card-header + %h2 Notes + .card-body + :growstuff_markdown + #{ @seed.description != "" ? strip_tags(@seed.description) : "No description given." } - if current_member - if @seed.tradable? && current_member != @seed.owner @@ -74,18 +55,21 @@ - else = render 'shared/signin_signup', to: 'request seeds' - = render 'seeds/descendants', seed: @seed - = render 'photos/item_photos', item: @seed, type: 'seed', photos: @photos - - .col-md-6 - = render @seed.crop + %section= render 'seeds/descendants', seed: @seed + %section.seed-photos + - @photos.each do |photo| + = render 'photos/hero', photo: photo + %p + %small + Or + = link_to "purchase seeds via Ebay", + crop_ebay_seeds_url(@seed.crop), target: "_blank", rel: "noopener noreferrer", class: 'btn' - if @seed.owner.location %p %small View other seeds, members to trade with and more near = link_to @seed.owner.location, place_path(@seed.owner.location, anchor: "seeds") - %p - %small - Or - = link_to "purchase seeds via Ebay", - crop_ebay_seeds_url(@seed.crop), target: "_blank", rel: "noopener noreferrer" + .col-md-4 + = render 'seeds/owner' + = render @seed.crop + diff --git a/app/views/timeline/_photos.html.haml b/app/views/timeline/_photos.html.haml index 12cddb1a2..732842c39 100644 --- a/app/views/timeline/_photos.html.haml +++ b/app/views/timeline/_photos.html.haml @@ -1,8 +1,11 @@ .media - = link_to(image_tag(photo.fullsize_url, width: 150, class: 'rounded'), photo) + = link_to(image_tag(photo.thumbnail_url, width: 150, class: 'rounded'), photo) .media-body %p %ul.associations + - photo.crops.each do |crop| + %li= render 'crops/tiny', crop: crop + - photo.plantings.each do |planting| %li = planting_icon diff --git a/app/views/timeline/index.html.haml b/app/views/timeline/index.html.haml index 1f374bc20..f94cafd1b 100644 --- a/app/views/timeline/index.html.haml +++ b/app/views/timeline/index.html.haml @@ -23,10 +23,7 @@ .pagination= will_paginate @seeds .col-md-3 .card - .card-header + .card-body %h3 Following - - @members.each do |member| - = link_to member do - %p - = render 'members/tiny', member: member - = member + - @members.each do |member| + = render 'members/tiny', member: member diff --git a/config/locales/en.yml b/config/locales/en.yml index 11dd0a781..e14b1a037 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -132,8 +132,8 @@ en: blurb: already_html: Or %{sign_in} if you already have an account intro: > - %{site_name} is a community of food gardeners. We're building an open source platform to help you learn about growing food, - track what you plant and harvest, and swap seeds and produce with other gardeners near you. + %{site_name} is a community of food gardeners. %{site_name}'s open source and open data platform + can predict when your plantings will be ready to harvest. The more you tell it, the better the predictions. perks: Join now for your free garden journal, harvest predictions, forums, and more. sign_in_linktext: sign in sign_up: Sign up @@ -208,6 +208,7 @@ en: days_until_harvest: "%{number} days" days_until_finished: "%{number} days" harvesting_now: harvesting now + data: 'The data on this page is available in the following formats:' layouts: header: account: Account @@ -289,7 +290,6 @@ en: default: Everyone's plantings owner_plantings: "%{owner} plantings" view_owners_profile: View %{owner}'s profile >> - the_data_on_this_page_is_available_in_the_following_formats: 'The data on this page is available in the following formats:' string: "%{crop} planting in %{garden} by %{owner}" progress: progress_0_not_planted_yet: 'Progress: 0% - not planted yet' diff --git a/config/routes.rb b/config/routes.rb index e1424d010..334bf106c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -69,6 +69,7 @@ Rails.application.routes.draw do get 'sunniness' => 'charts/crops#sunniness', constraints: { format: 'json' } get 'planted_from' => 'charts/crops#planted_from', constraints: { format: 'json' } get 'harvested_for' => 'charts/crops#harvested_for', constraints: { format: 'json' } + post :openfarm collection do get 'requested' diff --git a/db/migrate/20190902004225_add_openfarm_data_to_crops.rb b/db/migrate/20190902004225_add_openfarm_data_to_crops.rb new file mode 100644 index 000000000..f8cc4d43d --- /dev/null +++ b/db/migrate/20190902004225_add_openfarm_data_to_crops.rb @@ -0,0 +1,5 @@ +class AddOpenfarmDataToCrops < ActiveRecord::Migration[5.2] + def change + add_column :crops, :openfarm_data, :jsonb + end +end diff --git a/db/migrate/20190918033319_unique_urls.rb b/db/migrate/20190918033319_unique_urls.rb new file mode 100644 index 000000000..99b9caf42 --- /dev/null +++ b/db/migrate/20190918033319_unique_urls.rb @@ -0,0 +1,6 @@ +class UniqueUrls < ActiveRecord::Migration[5.2] + def change + add_index :photos, :fullsize_url, unique: true + add_index :photos, :thumbnail_url, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 4a450b704..7f611b3e6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -185,6 +185,7 @@ ActiveRecord::Schema.define(version: 2019_09_21_211652) do t.integer "median_lifespan" t.integer "median_days_to_first_harvest" t.integer "median_days_to_last_harvest" + t.jsonb "openfarm_data" t.index ["name"], name: "index_crops_on_name" t.index ["requester_id"], name: "index_crops_on_requester_id" t.index ["slug"], name: "index_crops_on_slug", unique: true @@ -427,6 +428,8 @@ ActiveRecord::Schema.define(version: 2019_09_21_211652) do t.datetime "date_taken" t.integer "likes_count", default: 0 t.string "source" + t.index ["fullsize_url"], name: "index_photos_on_fullsize_url", unique: true + t.index ["thumbnail_url"], name: "index_photos_on_thumbnail_url", unique: true end create_table "photos_plantings", id: false, force: :cascade do |t| diff --git a/db/seeds.rb b/db/seeds.rb index 378b98875..e3bc51088 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -115,6 +115,8 @@ def load_admin_users end def create_cropbot + return if Member.find_by(login_name: 'cropbot') + @cropbot_user = Member.new( login_name: "cropbot", email: Rails.application.config.bot_email, diff --git a/lib/tasks/openfarm.rake b/lib/tasks/openfarm.rake new file mode 100644 index 000000000..b6b6ce909 --- /dev/null +++ b/lib/tasks/openfarm.rake @@ -0,0 +1,9 @@ +namespace :openfarm do + desc "Retrieve crop info from open farm" + # usage: rake growstuff:admin_user name=skud + + task import: :environment do + Rails.logger = Logger.new(STDOUT) + OpenfarmService.new.import! + end +end diff --git a/spec/factories/planting.rb b/spec/factories/planting.rb index 24c092f82..8fb709d1c 100644 --- a/spec/factories/planting.rb +++ b/spec/factories/planting.rb @@ -38,5 +38,26 @@ FactoryBot.define do planted_at { Time.zone.local(2014, 7, 30) } finished_at { Time.zone.local(2014, 8, 30) } end + + factory :annual_planting do + crop { FactoryBot.create :annual_crop } + end + + factory :perennial_planting do + crop { FactoryBot.create :perennial_crop } + end + + factory :predicatable_planting do + crop do + crop = FactoryBot.create :annual_crop + FactoryBot.create :planting, crop: crop, planted_at: 10.days.ago + FactoryBot.create :planting, crop: crop, planted_at: 100.days.ago, finished_at: 50.days.ago + FactoryBot.create :planting, crop: crop, planted_at: 100.days.ago, finished_at: 51.days.ago + FactoryBot.create :planting, crop: crop, planted_at: 2.years.ago, finished_at: 50.days.ago + FactoryBot.create :planting, crop: crop, planted_at: 150.days.ago, finished_at: 100.days.ago + crop.update_lifespan_medians + crop + end + end end end diff --git a/spec/features/crops/request_new_crop_spec.rb b/spec/features/crops/request_new_crop_spec.rb index 4257e3a69..da38b1ec9 100644 --- a/spec/features/crops/request_new_crop_spec.rb +++ b/spec/features/crops/request_new_crop_spec.rb @@ -20,19 +20,17 @@ describe "Requesting a new crop" do it "Approve a request" do visit edit_crop_path(crop) - select "approved", from: "Approval status" - click_button "Save" + click_button "Approve and save" expect(page).to have_content "En wikipedia url is not a valid English Wikipedia URL" fill_in "en_wikipedia_url", with: "http://en.wikipedia.org/wiki/Aung_San_Suu_Kyi" - click_button "Save" + click_button "Approve and save" expect(page).to have_content "crop was successfully updated." end it "Rejecting a crop" do visit edit_crop_path(crop) - select "rejected", from: "Approval status" select "not edible", from: "Reason for rejection" - click_button "Save" + click_button "Reject" expect(page).to have_content "crop was successfully updated." end end diff --git a/spec/features/gardens/actions_spec.rb b/spec/features/gardens/actions_spec.rb index 0c9336a74..0dbfe1882 100644 --- a/spec/features/gardens/actions_spec.rb +++ b/spec/features/gardens/actions_spec.rb @@ -12,7 +12,7 @@ describe "Gardens" do describe '#index' do shared_examples "has buttons bar at top" do it "has buttons bar at top" do - within '.layout-actions' do + within '.nav' do expect(subject).to have_link 'Add a garden' expect(subject).to have_link 'My gardens' expect(subject).to have_link "Everyone's gardens" diff --git a/spec/features/gardens/gardens_spec.rb b/spec/features/gardens/gardens_spec.rb index 132997584..6b845bc50 100644 --- a/spec/features/gardens/gardens_spec.rb +++ b/spec/features/gardens/gardens_spec.rb @@ -12,13 +12,9 @@ describe "Planting a crop", js: true do it "View gardens" do visit gardens_path expect(page).to have_content "Everyone's gardens" - within '.layout-actions' do - click_link "My gardens" - end + click_link "My gardens" expect(page).to have_content "#{garden.owner.login_name}'s gardens" - within '.layout-actions' do - click_link "Everyone's gardens" - end + click_link "Everyone's gardens" expect(page).to have_content "Everyone's gardens" end diff --git a/spec/features/plantings/show_spec.rb b/spec/features/plantings/show_spec.rb new file mode 100644 index 000000000..e9d39fca3 --- /dev/null +++ b/spec/features/plantings/show_spec.rb @@ -0,0 +1,42 @@ +require "rails_helper" +require 'custom_matchers' + +describe "Display a planting", :js, :elasticsearch do + before { visit planting_path(planting) } + + context 'Perennial planted long ago' do + let(:planting) { FactoryBot.create :perennial_planting } + it { expect(find('.plantingfact--perennial')).to have_text 'Perennial' } + it { expect(find('.plantingfact--harveststitle')).to have_text 'Harvesting' } + end + + context 'Perennial finished' do + let(:planting) { FactoryBot.create :perennial_planting, planted_at: 6.years.ago, finished: true, finished_at: 1.year.ago } + it { expect(find('.plantingfact--perennial')).to have_text 'Perennial' } + it { expect(find('.plantingfact--harveststitle')).to have_text 'Harvested' } + end + + context 'Annual no predictions' do + let(:planting) { FactoryBot.create :annual_planting } + it { expect(find('.plantingfact--harveststitle')).to have_text 'Harvesting' } + end + + context 'Annual with predicted finish' do + let(:planting) { FactoryBot.create :predicatable_planting, planted_at: 1.day.ago } + it { expect(find('.plantingfact--dayssinceplanted')).to have_text '1' } + it { expect(find('.plantingfact--percentagegrown')).to have_text '2%' } + it { expect(find('.plantingfact--planttedat')).to have_text I18n.l(1.day.ago.to_date) } + it { expect(find('.plantingfact--harveststitle')).to have_text 'Harvesting' } + end + + context 'Annual finished' do + let(:planting) { FactoryBot.create :annual_planting, planted_at: 100.days.ago, finished: true, finished_at: 1.day.ago } + it { expect(find('.plantingfact--harveststitle')).to have_text 'Harvested' } + end + + context 'with quantity' do + let(:planting) { FactoryBot.create :planting, quantity: 100 } + it { expect(find('.plantingfact--quantity')).to have_text '100' } + it { expect(find('.plantingfact--harveststitle')).to have_text 'Harvesting' } + end +end diff --git a/spec/features/seeds/adding_seeds_spec.rb b/spec/features/seeds/adding_seeds_spec.rb index dd667bdb7..e2264eaa2 100644 --- a/spec/features/seeds/adding_seeds_spec.rb +++ b/spec/features/seeds/adding_seeds_spec.rb @@ -46,12 +46,12 @@ describe "Seeds", :js, :elasticsearch do end it { expect(page).to have_content "Successfully added maize seed to your stash" } - it { expect(page).to have_content "Quantity: 42" } - it { expect(page).to have_content "Days until maturity: 999–1999" } - it { expect(page).to have_content "certified organic" } - it { expect(page).to have_content "non-certified GMO-free" } - it { expect(page).to have_content "Heirloom? heirloom" } - it { expect(page).to have_content "It's killer." } + it { expect(find('.seedfacts--quantity')).to have_content "42" } + it { expect(find('.seedfacts--maturity')).to have_content "999–1999" } + it { expect(find('.seedtitle--organic')).to have_content "certified organic" } + it { expect(find('.seedtitle--gmo')).to have_content "non-certified GMO-free" } + it { expect(find('.seedtitle--heirloom')).to have_content "heirloom" } + it { expect(find('.seed--description')).to have_content "It's killer." } end describe "Adding a seed from crop page" do diff --git a/spec/features/seeds/misc_seeds_spec.rb b/spec/features/seeds/misc_seeds_spec.rb index b2205ee8a..53587ede5 100644 --- a/spec/features/seeds/misc_seeds_spec.rb +++ b/spec/features/seeds/misc_seeds_spec.rb @@ -68,25 +68,25 @@ describe "seeds", js: true do describe "view seeds with max and min days until maturity" do let(:seed) { FactoryBot.create :seed, days_until_maturity_min: 5, days_until_maturity_max: 7 } - it { expect(page).to have_content "Days until maturity: 5–7" } + it { expect(find('.seedfacts--maturity')).to have_content("5–7") } end describe "view seeds with only max days until maturity" do let(:seed) { FactoryBot.create :seed, days_until_maturity_max: 7 } - it { expect(page).to have_content "Days until maturity: 7" } + it { expect(find('.seedfacts--maturity')).to have_content("7") } end describe "view seeds with only min days until maturity" do let(:seed) { FactoryBot.create :seed, days_until_maturity_min: 5 } - it { expect(page).to have_content "Days until maturity: 5" } + it { expect(find('.seedfacts--maturity')).to have_content("5") } end describe "view seeds with neither max nor min days until maturity" do let(:seed) { FactoryBot.create :seed } - it { expect(page).to have_content "Days until maturity: unknown" } + it { expect(find('.seedfacts--maturity')).to have_content "unknown" } end end end diff --git a/spec/helpers/photos_helper_spec.rb b/spec/helpers/photos_helper_spec.rb index efc6ef07e..b24a254c7 100644 --- a/spec/helpers/photos_helper_spec.rb +++ b/spec/helpers/photos_helper_spec.rb @@ -2,16 +2,16 @@ require 'rails_helper' describe PhotosHelper do let(:crop) { FactoryBot.create :crop } + let(:crop_photo_of) { FactoryBot.create(:photo, source: 'openfarm') } + let(:crop_photo_flickr) { FactoryBot.create(:photo, source: 'flickr') } let(:garden) { FactoryBot.create :garden } - - let(:garden_photo) { FactoryBot.create(:photo, thumbnail_url: 'garden.jpg', owner: garden.owner) } - let(:planting) { FactoryBot.create :planting, crop: crop, owner: garden.owner } - let(:planting_photo) { FactoryBot.create(:photo, thumbnail_url: 'planting.jpg', owner: garden.owner) } - let(:harvest) { FactoryBot.create :harvest, crop: crop, owner: garden.owner } - let(:harvest_photo) { FactoryBot.create(:photo, thumbnail_url: 'harvest.jpg', owner: garden.owner) } - let(:seed) { FactoryBot.create :seed, crop: crop, owner: garden.owner } - let(:seed_photo) { FactoryBot.create(:photo, thumbnail_url: 'seed.jpg', owner: garden.owner) } + let(:planting) { FactoryBot.create :planting, crop: crop, owner: garden.owner } + let(:planting_photo) { FactoryBot.create(:photo, owner: garden.owner) } + let(:harvest) { FactoryBot.create :harvest, crop: crop, owner: garden.owner } + let(:harvest_photo) { FactoryBot.create(:photo, owner: garden.owner) } + let(:seed) { FactoryBot.create :seed, crop: crop, owner: garden.owner } + let(:seed_photo) { FactoryBot.create(:photo, owner: garden.owner) } describe "crops" do subject { crop_image_path(crop) } @@ -22,7 +22,7 @@ describe PhotosHelper do before { planting.photos << planting_photo } it "uses planting photos" do - expect(subject).to eq planting_photo.thumbnail_url + expect(subject).to eq planting_photo.fullsize_url end end @@ -30,7 +30,7 @@ describe PhotosHelper do before { harvest.photos << harvest_photo } it "uses harvest photos" do - expect(subject).to eq harvest_photo.thumbnail_url + expect(subject).to eq harvest_photo.fullsize_url end end @@ -38,7 +38,7 @@ describe PhotosHelper do before { seed.photos << seed_photo } it "uses seed photos" do - expect(subject).to eq seed_photo.thumbnail_url + expect(subject).to eq seed_photo.fullsize_url end end end @@ -48,10 +48,10 @@ describe PhotosHelper do it { is_expected.to eq 'placeholder_600.png' } - describe "uses garden's own photo" do + describe "has a flickr photo" do + let(:garden_photo) { FactoryBot.create(:photo, owner: garden.owner, source: 'flickr') } before { garden.photos << garden_photo } - - it { is_expected.to eq garden_photo.thumbnail_url } + it { is_expected.to eq garden_photo.fullsize_url } end end @@ -59,10 +59,11 @@ describe PhotosHelper do subject { planting_image_path(planting) } it { is_expected.to eq 'placeholder_600.png' } + describe "uses planting's own photo" do before { planting.photos << planting_photo } - it { is_expected.to eq planting_photo.thumbnail_url } + it { is_expected.to eq planting_photo.fullsize_url } end end @@ -70,10 +71,11 @@ describe PhotosHelper do subject { harvest_image_path(harvest) } it { is_expected.to eq 'placeholder_600.png' } + describe "uses harvest's own photo" do before { harvest.photos << harvest_photo } - it { is_expected.to eq harvest_photo.thumbnail_url } + it { is_expected.to eq harvest_photo.fullsize_url } end end @@ -85,7 +87,7 @@ describe PhotosHelper do describe "uses seed's own photo" do before { seed.photos << seed_photo } - it { is_expected.to eq seed_photo.thumbnail_url } + it { is_expected.to eq seed_photo.fullsize_url } end end end diff --git a/spec/views/crops/_planting_advice.html.haml_spec.rb b/spec/views/crops/_planting_advice.html.haml_spec.rb deleted file mode 100644 index 59e635b45..000000000 --- a/spec/views/crops/_planting_advice.html.haml_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'rails_helper' - -describe "crops/_planting_advice" do - subject { rendered } - - let(:planting) { FactoryBot.create(:planting) } - - shared_context "render planting_advice" do - before { render 'crops/planting_advice', crop: planting.crop } - end - - describe "sunniness" do - context "with no sunniness set" do - include_examples "render planting_advice" - it "doesn't show sunniness" do - expect(subject).to have_content "Plant in: not known." - end - end - - context "with sunniness frequencies" do - before { FactoryBot.create(:sunny_planting, crop: planting.crop) } - - include_examples "render planting_advice" - it { is_expected.to have_content "Plant in:" } - it { is_expected.to have_content "sun (1)" } - end - - context "with multiple sunniness frequencies" do - before do - FactoryBot.create_list(:sunny_planting, 2, crop: planting.crop) - FactoryBot.create(:shady_planting, crop: planting.crop) - end - - include_examples "render planting_advice" - it { is_expected.to have_content "Plant in:" } - it { is_expected.to have_content "sun (2), shade (1)" } - end - end - - describe "planted from" do - context "when none are set" do - include_examples "render planting_advice" - it "doesn't show planted_from " do - expect(subject).to have_content "Plant from: not known." - end - end - - context "with planted_from frequencies" do - before { FactoryBot.create(:seed_planting, crop: planting.crop) } - - include_examples "render planting_advice" - it { is_expected.to have_content "Plant from:" } - it { is_expected.to have_content "seed (1)" } - end - - context "with multiple planted_from frequencies" do - before do - FactoryBot.create_list(:seed_planting, 2, crop: planting.crop) - FactoryBot.create(:cutting_planting, crop: planting.crop) - end - - include_examples "render planting_advice" - it { is_expected.to have_content "Plant from:" } - it { is_expected.to have_content "seed (2), cutting (1)" } - end - end -end diff --git a/spec/views/harvests/index.html.haml_spec.rb b/spec/views/harvests/index.html.haml_spec.rb index 461749f0b..294256ade 100644 --- a/spec/views/harvests/index.html.haml_spec.rb +++ b/spec/views/harvests/index.html.haml_spec.rb @@ -27,7 +27,7 @@ describe "harvests/index" do it "provides data links" do render - rendered.should have_content "The data on this page is available in the following formats:" + expect(rendered).to have_content "The data on this page is available in the following formats:" assert_select "a", href: harvests_path(format: 'csv') assert_select "a", href: harvests_path(format: 'json') end diff --git a/spec/views/harvests/show.html.haml_spec.rb b/spec/views/harvests/show.html.haml_spec.rb index f3c17f2b5..4a8053924 100644 --- a/spec/views/harvests/show.html.haml_spec.rb +++ b/spec/views/harvests/show.html.haml_spec.rb @@ -14,7 +14,7 @@ describe "harvests/show" do describe "renders attributes" do it { is_expected.to have_content harvest.crop.name } - it { is_expected.to have_content harvest.harvested_at.to_s } + it { is_expected.to have_content I18n.l(harvest.harvested_at) } it { is_expected.to have_content harvest.plant_part.to_s } end end diff --git a/spec/views/seeds/show.html.haml_spec.rb b/spec/views/seeds/show.html.haml_spec.rb index 1c2e88442..34525fbb6 100644 --- a/spec/views/seeds/show.html.haml_spec.rb +++ b/spec/views/seeds/show.html.haml_spec.rb @@ -29,7 +29,7 @@ describe "seeds/show" do end it "shows tradable attributes" do - expect(rendered).to have_content "Will trade: locally" + expect(rendered).to have_content "Will trade locally" end it "shows button to send message" do From 3eb30a55550de2a13e1bad724bc7ad7acdb44210 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 28 Sep 2019 17:44:37 +1200 Subject: [PATCH 19/27] Removed duplicate crop info --- app/views/crops/show.html.haml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index 68e841383..bb4a25287 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -14,25 +14,6 @@ %li.breadcrumb-item.active= link_to @crop.name.capitalize, @crop = render 'approval_status_message', crop: @crop -.jumbotron - .row - .col-md-9 - %h1 - %strong= @crop.name.capitalize - - unless @crop.approved? - %badge.badge-warning=@crop.approval_status - %small.text-muted= @crop.default_scientific_name - %p.text-muted - - if !@crop.plantings.empty? - #{@crop.name.capitalize} has been planted - = pluralize(@crop.plantings.size, "time") - by #{ENV['GROWSTUFF_SITE_NAME']} members. - - else - Nobody is growing this yet. You could be the first! - .col-md-3 - = image_tag crop_image_path(@crop), - class: 'img-responsive shadow rounded crop-hero-photo', alt: 'photo of crop' - .jumbotron= render 'crops/info' .row From 0a7180723799c68269a2a6f18e81effa91fd1ceb Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sat, 28 Sep 2019 18:38:58 +1200 Subject: [PATCH 20/27] Stop using rails-assets.org (#2194) --- Gemfile | 2 +- Gemfile.lock | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 2672e0aaf..98f5a7e7b 100644 --- a/Gemfile +++ b/Gemfile @@ -46,7 +46,7 @@ gem 'gibbon', '~>1.2.0' # for Mailchimp newsletter subscriptions # Maps gem 'leaflet-rails' -gem 'rails-assets-leaflet.markercluster', source: 'https://rails-assets.org' +gem 'rails-assets-leaflet.markercluster' gem 'pg', '< 1.0.0' # Upstream bug, see https://github.com/Growstuff/growstuff/pull/1539 gem 'ruby-units' # for unit conversion diff --git a/Gemfile.lock b/Gemfile.lock index 5dc18108e..b6eb02eaf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,5 @@ GEM remote: https://rubygems.org/ - remote: https://rails-assets.org/ specs: abstract_type (0.0.7) actioncable (5.2.2.1) @@ -632,7 +631,7 @@ DEPENDENCIES puma rack-protection (>= 2.0.1) rails (= 5.2.2.1) - rails-assets-leaflet.markercluster! + rails-assets-leaflet.markercluster rails-controller-testing rails_12factor rake (>= 10.0.0) From d39dc65c4eaecdf219ec6f796b10a200328210b8 Mon Sep 17 00:00:00 2001 From: bestest-mensch <16200338+bestest-mensch@users.noreply.github.com> Date: Sat, 5 Oct 2019 22:06:22 -0500 Subject: [PATCH 21/27] small ui tweak --- app/views/gardens/show.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/gardens/show.html.haml b/app/views/gardens/show.html.haml index ae51892fa..9384e088a 100644 --- a/app/views/gardens/show.html.haml +++ b/app/views/gardens/show.html.haml @@ -69,7 +69,8 @@ - @finished_plantings.each do |planting| = render "plantings/thumbnail", planting: planting - else - %p Nothing has been planted here. + .col-md-12 + %p Nothing has been planted here. .col-md-3 .card .card-image From 01df35e5a656101527ca92450d971216a2863f69 Mon Sep 17 00:00:00 2001 From: bestest-mensch <16200338+bestest-mensch@users.noreply.github.com> Date: Sat, 5 Oct 2019 22:18:21 -0500 Subject: [PATCH 22/27] update contributors --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 01aeaaba7..1e308c839 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -88,6 +88,7 @@ submit the change with your pull request. - Ahmed Shahin / [codeminator](https://www.github.com/codeminator) - Brandon Baker / [brandonbaker40](https://github.com/brandonbaker40) - Alex Darr / [apdarr](https://github.com/apdarr) +- Taylor William / [bestest-mensch](https://github.com/bestest-mensch) ## Bots From 80fb4f5fe6a1a8f5ab1478a432afbd5305691e3f Mon Sep 17 00:00:00 2001 From: bestest-mensch <16200338+bestest-mensch@users.noreply.github.com> Date: Sat, 5 Oct 2019 21:23:37 -0500 Subject: [PATCH 23/27] add ability to delete multiple conversations at once --- app/controllers/conversations_controller.rb | 7 ++ app/views/conversations/index.haml | 105 ++++++++++---------- config/routes.rb | 6 +- spec/features/conversations/index_spec.rb | 4 +- 4 files changed, 68 insertions(+), 54 deletions(-) diff --git a/app/controllers/conversations_controller.rb b/app/controllers/conversations_controller.rb index 67cf92211..52b92a59a 100644 --- a/app/controllers/conversations_controller.rb +++ b/app/controllers/conversations_controller.rb @@ -33,6 +33,13 @@ class ConversationsController < ApplicationController redirect_to conversations_path(box: params[:box]) end + def destroy_multiple + Mailboxer::Conversation.where(id: params[:conversation_ids]).each do |conversation| + conversation.move_to_trash(current_member) + end + redirect_to conversations_path(box: params[:box]) + end + private def mailbox diff --git a/app/views/conversations/index.haml b/app/views/conversations/index.haml index 81f38c125..550ecf9b7 100644 --- a/app/views/conversations/index.haml +++ b/app/views/conversations/index.haml @@ -3,55 +3,58 @@ %li.breadcrumb-item= link_to 'Conversations', conversations_path %li.breadcrumb-item.active= link_to @box, conversations_path(box: @box) -.row - .col-md-2 - .col-md-10 - %h1= @box - - unless @conversations.empty? - = will_paginate @conversations -.row - .col-md-2.list-group - - @boxes.each do |box_name, counts| - = link_to conversations_path(box: box_name), class: "nav-link list-group-item d-flex justify-content-between #{box_name == @box ? 'active' : ''} #{box_name}" do - - if counts['unread'].positive? - %span.badge.badge-info=counts['unread'] - - else - %span - %span - = icon 'fas', box_name - = box_name += form_tag destroy_multiple_conversations_path, method: :delete do + .row.py-4 + .col-2.offset-md-2 + %h1= @box + .col-8 + = button_tag(type: 'submit', class: 'btn btn-default') do + = icon 'fas', 'trash-alt' + = 'Delete Selected' - .col-md-10 - .list-group - - @conversations.each do |conversation| - .list-group-item - .row - .col-md-1 - - if conversation.receipts_for(current_member).last.is_unread? - %h1= icon 'far', 'envelope' - - else - %h1.text-muted= icon 'far', 'envelope-open' - .col-md-10 - .text-right.float-right - - conversation.recipients.each do |member| - - if member != current_member - = render 'members/tiny', member: member - = link_to conversation_path(conversation) do - .conversation - %h5.mb-2.h5 - - if conversation.receipts_for(current_member).last.is_unread? - %strong= conversation.subject - - else - = conversation.subject - %small - #{time_ago_in_words conversation.messages.last.created_at} ago - %span.text-muted= conversation.messages.last.created_at - = truncate(strip_tags(conversation.messages.last.body), length: 150, separator: ' ', omission: '... ') - .col-md-1 - - if @box == 'trash' - = link_to conversation_path(conversation, box: @box), method: :put, class: 'restore' do - = icon 'fas', 'trash-restore' - - else - = link_to delete_icon, conversation_path(conversation, box: @box), method: :delete, class: 'delete text-danger' - - unless @conversations.empty? - = will_paginate @conversations + .row + .col-md-2.py-4 + - @boxes.each do |box_name, counts| + = link_to conversations_path(box: box_name), class: "nav-link list-group-item d-flex justify-content-between #{box_name == @box ? 'active' : ''} #{box_name}" do + - if counts['unread'].positive? + %span.badge.badge-info=counts['unread'] + - else + %span + %span + = icon 'fas', box_name + = box_name + + .col-md-10 + .list-group + - @conversations.each do |conversation| + .list-group-item + .row + .col-md-1 + - if conversation.receipts_for(current_member).last.is_unread? + %h1= icon 'far', 'envelope' + - else + %h1.text-muted= icon 'far', 'envelope-open' + .col-md-10 + .text-right.float-right + - conversation.recipients.each do |member| + - if member != current_member + = render 'members/tiny', member: member + = link_to conversation_path(conversation) do + .conversation + %h5.mb-2.h5 + - if conversation.receipts_for(current_member).last.is_unread? + %strong= conversation.subject + - else + = conversation.subject + %small + #{time_ago_in_words conversation.messages.last.created_at} ago + %span.text-muted= conversation.messages.last.created_at + = truncate(strip_tags(conversation.messages.last.body), length: 150, separator: ' ', omission: '... ') + .col-md-1 + - if @box == 'trash' + = link_to conversation_path(conversation, box: @box), method: :put, class: 'restore' do + = icon 'fas', 'trash-restore' + - else + = check_box_tag 'conversation_ids[]', conversation.id, false, class: 'selectable' + - unless @conversations.empty? + = will_paginate @conversations diff --git a/config/routes.rb b/config/routes.rb index 334bf106c..1caa9ebe5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -99,7 +99,11 @@ Rails.application.routes.draw do end resources :messages - resources :conversations + resources :conversations do + collection do + delete 'destroy_multiple' + end + end resources :places, only: %i(index show), param: :place do get 'search', on: :collection diff --git a/spec/features/conversations/index_spec.rb b/spec/features/conversations/index_spec.rb index 850e42236..8c13ad6ee 100644 --- a/spec/features/conversations/index_spec.rb +++ b/spec/features/conversations/index_spec.rb @@ -20,8 +20,8 @@ describe "Conversations", :js do describe 'deleting' do before do - # delete button - click_link class: 'delete' + check 'conversation_ids[]' + click_button 'Delete Selected' end describe 'view trash' do From 9f8e2e65be7af76391dff200fe00b603a35828e1 Mon Sep 17 00:00:00 2001 From: bestest-mensch <16200338+bestest-mensch@users.noreply.github.com> Date: Sun, 6 Oct 2019 16:12:46 -0500 Subject: [PATCH 24/27] update/add specs --- spec/features/conversations/index_spec.rb | 43 ++++++++++++++++ spec/rails_helper.rb | 1 + spec/requests/conversations_spec.rb | 62 +++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 spec/requests/conversations_spec.rb diff --git a/spec/features/conversations/index_spec.rb b/spec/features/conversations/index_spec.rb index 8c13ad6ee..1746a314c 100644 --- a/spec/features/conversations/index_spec.rb +++ b/spec/features/conversations/index_spec.rb @@ -39,4 +39,47 @@ describe "Conversations", :js do end end end + + describe 'deleting conversations' do + it 'deletes multiple conversations from the inbox' do + sender.send_message(recipient, 'this is a message', 'message 1') + sender.send_message(recipient, 'this is another message', 'follow up message') + + visit root_path + click_link 'Your Stuff' + click_link 'Inbox' + + all('input[type=checkbox]').each do |checkbox| + checkbox.click + end + + click_button 'Delete Selected' + + expect(page).not_to have_content 'this is a message' + expect(page).not_to have_content 'this is another message' + end + + it 'deletes multiple conversations from the sentbox' do + sender.send_message(recipient, 'this is a message', 'message 1') + sender.send_message(recipient, 'this is another message', 'follow up message') + + visit root_path + click_link 'Your Stuff' + click_link 'Inbox' + + expect(page).to have_selector('.sent') + find('.sent').click + + all('input[type=checkbox]').each do |checkbox| + checkbox.click + end + + click_button 'Delete Selected' + + expect(page).to have_selector('.sent') + find('.sent').click + expect(page).not_to have_content 'this is a message' + expect(page).not_to have_content 'this is another message' + end + end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index c5dbe582b..d780aedb2 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -96,6 +96,7 @@ RSpec.configure do |config| # controller specs require this to work with Devise # see https://github.com/plataformatec/devise/wiki/How-To%3a-Controllers-and-Views-tests-with-Rails-3-%28and-rspec%29 config.include Devise::Test::ControllerHelpers, type: :controller + config.include Devise::Test::IntegrationHelpers, type: :request config.extend ControllerMacros, type: :controller # Allow just create(:factory) instead of needing to specify FactoryBot.create(:factory) diff --git a/spec/requests/conversations_spec.rb b/spec/requests/conversations_spec.rb new file mode 100644 index 000000000..1ed996685 --- /dev/null +++ b/spec/requests/conversations_spec.rb @@ -0,0 +1,62 @@ +require 'rails_helper' + +describe 'Converstions' do + describe 'DELETE destroy_multiple' do + let!(:member) { create(:admin_member) } + + before do + sign_in member + end + + it 'redirects to the conversations inbox' do + delete '/conversations/destroy_multiple', params: { conversation_ids: [] } + expect(response).to redirect_to '/conversations' + follow_redirect! + expect(response).to render_template(:index) + expect(response).to have_http_status(200) + end + + it 'allows users to trash multiple inbox conversations' do + first_conversation = create(:notification, recipient: member) + second_conversation = create(:notification, recipient: member) + conversations_to_trash = [first_conversation.id, second_conversation.id] + + # we dont actually destroy the messages, we move them to the trash folder + expect do + delete '/conversations/destroy_multiple', params: { conversation_ids: conversations_to_trash, box: 'inbox' } + end.to_not change(Mailboxer::Conversation, :count) + + expect(member.mailbox.inbox.count).to eq 0 + expect(member.mailbox.trash.count).to eq 2 + end + + it 'only deletes conversations for the current user' do + second_member = create(:admin_member) + first_conversation = create(:notification, sender: member, recipient: second_member) + second_conversation = create(:notification, sender: member, recipient: second_member) + conversations_to_trash = [first_conversation.id, second_conversation.id] + + # we dont actually destroy the messages, we move them to the trash folder + expect do + delete '/conversations/destroy_multiple', params: { conversation_ids: conversations_to_trash } + end.to_not change(Mailboxer::Conversation, :count) + + expect(second_member.mailbox.inbox.count).to eq 2 + expect(second_member.mailbox.trash.count).to eq 0 + end + + it 'allows users to trash multiple sent conversations' do + first_conversation = create(:notification, sender: member) + second_conversation = create(:notification, sender: member) + conversations_to_trash = [first_conversation.id, second_conversation.id] + + # we dont actually destroy the messages, we move them to the trash folder + expect do + delete '/conversations/destroy_multiple', params: { conversation_ids: conversations_to_trash, box: 'sent' } + end.to_not change(Mailboxer::Conversation, :count) + + expect(member.mailbox.sentbox.count).to eq 0 + expect(member.mailbox.trash.count).to eq 2 + end + end +end From 1e1b9f5ef5e5c764c03e312b2cf30bba56aff043 Mon Sep 17 00:00:00 2001 From: bestest-mensch <16200338+bestest-mensch@users.noreply.github.com> Date: Sun, 6 Oct 2019 16:13:07 -0500 Subject: [PATCH 25/27] scope conversations delete multiple to current user --- app/controllers/conversations_controller.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/controllers/conversations_controller.rb b/app/controllers/conversations_controller.rb index 52b92a59a..a8b806a9d 100644 --- a/app/controllers/conversations_controller.rb +++ b/app/controllers/conversations_controller.rb @@ -34,7 +34,12 @@ class ConversationsController < ApplicationController end def destroy_multiple - Mailboxer::Conversation.where(id: params[:conversation_ids]).each do |conversation| + conversations = if @box.eql? 'sent' + mailbox.sentbox + else + mailbox.inbox + end + conversations.where(id: params[:conversation_ids]).each do |conversation| conversation.move_to_trash(current_member) end redirect_to conversations_path(box: params[:box]) From d72ec5890a13df2e6aeaef5824f99cd175b88094 Mon Sep 17 00:00:00 2001 From: bestest-mensch <16200338+bestest-mensch@users.noreply.github.com> Date: Sun, 6 Oct 2019 16:53:34 -0500 Subject: [PATCH 26/27] address code climate issues --- spec/features/conversations/index_spec.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/spec/features/conversations/index_spec.rb b/spec/features/conversations/index_spec.rb index 1746a314c..969fc447c 100644 --- a/spec/features/conversations/index_spec.rb +++ b/spec/features/conversations/index_spec.rb @@ -49,10 +49,7 @@ describe "Conversations", :js do click_link 'Your Stuff' click_link 'Inbox' - all('input[type=checkbox]').each do |checkbox| - checkbox.click - end - + all('input[type=checkbox]').each(&:click) click_button 'Delete Selected' expect(page).not_to have_content 'this is a message' @@ -70,10 +67,7 @@ describe "Conversations", :js do expect(page).to have_selector('.sent') find('.sent').click - all('input[type=checkbox]').each do |checkbox| - checkbox.click - end - + all('input[type=checkbox]').each(&:click) click_button 'Delete Selected' expect(page).to have_selector('.sent') From b0c8b11246f6424550c31c0bfe29d13837bc60dd Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Tue, 8 Oct 2019 11:06:53 +1300 Subject: [PATCH 27/27] =?UTF-8?q?=F0=9F=93=9D=20Inline=20editing=20and=20d?= =?UTF-8?q?isplay=20tidy=20ups=20(#2200)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Inline editing and display tidy ups --- app/assets/images/icons/COPYRIGHT | 1 + app/assets/images/icons/add-photo.svg | 1 + app/assets/images/icons/ant.svg | 1 + app/assets/images/icons/bee.svg | 1 + app/assets/images/icons/bug.svg | 1 + app/assets/images/icons/butterfly.svg | 1 + app/assets/images/icons/cat.svg | 1 + app/assets/images/icons/delete.svg | 12 +- app/assets/images/icons/earth-worm.svg | 1 + app/assets/images/icons/edit.svg | 1 + app/assets/images/icons/finish.svg | 1 + app/assets/images/icons/garden.svg | 26 ----- app/assets/images/icons/gardener.svg | 1 + app/assets/images/icons/gardens.svg | 1 + app/assets/images/icons/grass.svg | 1 + app/assets/images/icons/harvest-add.svg | 10 ++ app/assets/images/icons/harvest.svg | 6 +- app/assets/images/icons/home.svg | 5 - app/assets/images/icons/hose.svg | 1 + app/assets/images/icons/insect.svg | 1 + app/assets/images/icons/ladybird.svg | 1 + app/assets/images/icons/notification.svg | 1 + app/assets/images/icons/photo.svg | 1 + app/assets/images/icons/plant-seeds.svg | 3 - app/assets/images/icons/plant_parts/bark.svg | 1 + app/assets/images/icons/plant_parts/bulb.svg | 1 + .../images/icons/plant_parts/flower.svg | 1 + app/assets/images/icons/plant_parts/fruit.svg | 1 + .../images/icons/plant_parts/leaves.svg | 1 + app/assets/images/icons/plant_parts/pod.svg | 1 + app/assets/images/icons/plant_parts/seeds.svg | 1 + app/assets/images/icons/plant_parts/tuber.svg | 1 + app/assets/images/icons/planting-add.svg | 13 +++ app/assets/images/icons/planting-hand.svg | 1 + app/assets/images/icons/planting-sun.svg | 1 + app/assets/images/icons/planting.svg | 6 +- app/assets/images/icons/post.svg | 7 +- app/assets/images/icons/rabbit.svg | 1 + app/assets/images/icons/seed-add.svg | 15 +++ app/assets/images/icons/seeds-colour.svg | 18 --- app/assets/images/icons/seeds.svg | 17 ++- app/assets/images/icons/slug-eating.svg | 1 + app/assets/images/icons/slug.svg | 1 + app/assets/images/icons/snail.svg | 1 + app/assets/images/icons/spiderweb.svg | 1 + app/assets/images/icons/sprinkler.svg | 1 + app/assets/images/icons/sprout-add.svg | 11 ++ app/assets/images/icons/sprout.svg | 1 + app/assets/images/icons/stones.svg | 1 + app/assets/images/icons/timeline.svg | 23 ++++ app/assets/images/icons/watering-can.svg | 1 + app/assets/images/icons/wheelbarrow.svg | 1 + app/assets/javascripts/datepicker.js | 3 + app/assets/javascripts/editable.js | 6 + app/assets/javascripts/plantings.js.coffee | 6 - app/assets/javascripts/seeds.js.coffee | 6 - app/assets/stylesheets/_crops.scss | 38 +++---- app/assets/stylesheets/_harvests.scss | 34 ++++++ app/assets/stylesheets/_members.scss | 15 --- app/assets/stylesheets/_seeds.scss | 10 ++ app/assets/stylesheets/_variables.scss | 3 +- app/assets/stylesheets/overrides.scss | 68 ++++++++--- app/controllers/crops_controller.rb | 7 +- app/controllers/gardens_controller.rb | 16 +-- app/controllers/harvests_controller.rb | 6 +- app/controllers/plantings_controller.rb | 1 + app/controllers/seeds_controller.rb | 23 ++-- app/helpers/application_helper.rb | 14 +-- app/helpers/buttons_helper.rb | 2 +- app/helpers/editable_form_helper.rb | 6 + app/helpers/gardens_helper.rb | 4 - app/helpers/icons_helper.rb | 35 ++++-- app/helpers/plantings_helper.rb | 8 +- app/models/concerns/predict_planting.rb | 4 + app/models/crop.rb | 7 +- app/models/harvest.rb | 12 +- app/models/photo.rb | 4 +- app/models/planting.rb | 2 + app/models/seed.rb | 2 +- app/views/crops/_actions.html.haml | 38 ++++--- app/views/crops/_form.html.haml | 2 + app/views/crops/_hierarchy.html.haml | 2 + app/views/crops/_info.haml | 7 +- app/views/crops/_posts.html.haml | 4 +- app/views/crops/_predictions.html.haml | 15 ++- app/views/crops/_tiny.html.haml | 8 +- app/views/crops/index.html.haml | 28 ++--- app/views/crops/show.html.haml | 40 ++++--- app/views/gardens/index.html.haml | 38 +++++-- app/views/gardens/show.html.haml | 22 ++-- app/views/harvests/_card.html.haml | 2 +- app/views/harvests/_thumbnail.html.haml | 19 ++-- app/views/harvests/index.html.haml | 1 - app/views/harvests/show.html.haml | 86 ++++++++------ app/views/home/_blurb.html.haml | 2 +- app/views/home/_crops.html.haml | 2 +- app/views/home/index.html.haml | 16 ++- app/views/layouts/_header.html.haml | 64 ++++++++--- app/views/layouts/_nav.haml | 28 +++-- app/views/layouts/_pagination.html.haml | 1 - app/views/layouts/application.html.haml | 17 ++- app/views/layouts/modal.html.haml | 11 ++ app/views/members/_tiny.haml | 2 +- app/views/photos/_tiny.html.haml | 3 + app/views/photos/show.html.haml | 29 +++-- app/views/plant_parts/index.html.haml | 38 ++++--- app/views/plantings/_badges.html.haml | 10 +- app/views/plantings/_card.html.haml | 14 +-- app/views/plantings/_descendants.html.haml | 12 +- app/views/plantings/_facts.haml | 107 +++++++++++------- app/views/plantings/_harvests.html.haml | 15 ++- app/views/plantings/_photos.haml | 4 +- app/views/plantings/_progress.html.haml | 9 +- app/views/plantings/_progress_list.haml | 15 +++ app/views/plantings/_quick_actions.haml | 22 ++-- app/views/plantings/_tiny.html.haml | 4 + app/views/plantings/index.html.haml | 32 +++--- app/views/plantings/show.html.haml | 16 ++- app/views/posts/_single.html.haml | 29 ----- app/views/posts/show.html.haml | 4 +- app/views/scientific_names/_form.html.haml | 2 +- app/views/seeds/_card.html.haml | 6 +- app/views/seeds/_facts.html.haml | 34 ++++-- app/views/seeds/_seed.haml | 2 +- app/views/seeds/index.html.haml | 44 +++---- app/views/seeds/show.html.haml | 107 +++++++++--------- app/views/shared/_global_actions.html.haml | 25 ---- app/views/shared/_signin_signup.html.haml | 13 +-- app/views/shared/editable/_date.html.haml | 11 ++ app/views/shared/editable/_form.html.haml | 18 +++ config/locales/en.yml | 3 + .../charts/gardens_controller_spec.rb | 4 +- spec/features/crops/crop_detail_page_spec.rb | 12 +- spec/features/gardens/index_spec.rb | 10 +- .../harvests/harvesting_a_crop_spec.rb | 16 +-- .../plantings/planting_a_crop_spec.rb | 18 +-- spec/features/plantings/show_spec.rb | 8 +- spec/features/seeds/adding_seeds_spec.rb | 7 +- spec/features/seeds/misc_seeds_spec.rb | 3 +- spec/features/shared_examples/append_date.rb | 3 +- spec/views/photos/index.html.haml_spec.rb | 2 +- 141 files changed, 1001 insertions(+), 717 deletions(-) create mode 100644 app/assets/images/icons/COPYRIGHT create mode 100644 app/assets/images/icons/add-photo.svg create mode 100644 app/assets/images/icons/ant.svg create mode 100644 app/assets/images/icons/bee.svg create mode 100644 app/assets/images/icons/bug.svg create mode 100644 app/assets/images/icons/butterfly.svg create mode 100644 app/assets/images/icons/cat.svg create mode 100644 app/assets/images/icons/earth-worm.svg create mode 100644 app/assets/images/icons/edit.svg create mode 100644 app/assets/images/icons/finish.svg delete mode 100644 app/assets/images/icons/garden.svg create mode 100644 app/assets/images/icons/gardener.svg create mode 100644 app/assets/images/icons/gardens.svg create mode 100644 app/assets/images/icons/grass.svg create mode 100644 app/assets/images/icons/harvest-add.svg delete mode 100644 app/assets/images/icons/home.svg create mode 100644 app/assets/images/icons/hose.svg create mode 100644 app/assets/images/icons/insect.svg create mode 100644 app/assets/images/icons/ladybird.svg create mode 100644 app/assets/images/icons/notification.svg create mode 100644 app/assets/images/icons/photo.svg delete mode 100644 app/assets/images/icons/plant-seeds.svg create mode 100644 app/assets/images/icons/plant_parts/bark.svg create mode 100644 app/assets/images/icons/plant_parts/bulb.svg create mode 100644 app/assets/images/icons/plant_parts/flower.svg create mode 100644 app/assets/images/icons/plant_parts/fruit.svg create mode 100644 app/assets/images/icons/plant_parts/leaves.svg create mode 100644 app/assets/images/icons/plant_parts/pod.svg create mode 100644 app/assets/images/icons/plant_parts/seeds.svg create mode 100644 app/assets/images/icons/plant_parts/tuber.svg create mode 100644 app/assets/images/icons/planting-add.svg create mode 100644 app/assets/images/icons/planting-hand.svg create mode 100644 app/assets/images/icons/planting-sun.svg create mode 100644 app/assets/images/icons/rabbit.svg create mode 100644 app/assets/images/icons/seed-add.svg delete mode 100644 app/assets/images/icons/seeds-colour.svg create mode 100644 app/assets/images/icons/slug-eating.svg create mode 100644 app/assets/images/icons/slug.svg create mode 100644 app/assets/images/icons/snail.svg create mode 100644 app/assets/images/icons/spiderweb.svg create mode 100644 app/assets/images/icons/sprinkler.svg create mode 100644 app/assets/images/icons/sprout-add.svg create mode 100644 app/assets/images/icons/sprout.svg create mode 100644 app/assets/images/icons/stones.svg create mode 100644 app/assets/images/icons/timeline.svg create mode 100644 app/assets/images/icons/watering-can.svg create mode 100644 app/assets/images/icons/wheelbarrow.svg create mode 100644 app/assets/javascripts/datepicker.js create mode 100644 app/assets/javascripts/editable.js delete mode 100644 app/assets/javascripts/plantings.js.coffee delete mode 100644 app/assets/javascripts/seeds.js.coffee create mode 100644 app/helpers/editable_form_helper.rb delete mode 100644 app/views/layouts/_pagination.html.haml create mode 100644 app/views/layouts/modal.html.haml create mode 100644 app/views/photos/_tiny.html.haml create mode 100644 app/views/plantings/_progress_list.haml create mode 100644 app/views/plantings/_tiny.html.haml delete mode 100644 app/views/shared/_global_actions.html.haml create mode 100644 app/views/shared/editable/_date.html.haml create mode 100644 app/views/shared/editable/_form.html.haml diff --git a/app/assets/images/icons/COPYRIGHT b/app/assets/images/icons/COPYRIGHT new file mode 100644 index 000000000..acf08b86d --- /dev/null +++ b/app/assets/images/icons/COPYRIGHT @@ -0,0 +1 @@ +Icons in this folder attributable to Icons8.com. Used with permission. diff --git a/app/assets/images/icons/add-photo.svg b/app/assets/images/icons/add-photo.svg new file mode 100644 index 000000000..a3a042c10 --- /dev/null +++ b/app/assets/images/icons/add-photo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/ant.svg b/app/assets/images/icons/ant.svg new file mode 100644 index 000000000..da94eac67 --- /dev/null +++ b/app/assets/images/icons/ant.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/bee.svg b/app/assets/images/icons/bee.svg new file mode 100644 index 000000000..fa3cdfc99 --- /dev/null +++ b/app/assets/images/icons/bee.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/bug.svg b/app/assets/images/icons/bug.svg new file mode 100644 index 000000000..bc5b5da5f --- /dev/null +++ b/app/assets/images/icons/bug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/butterfly.svg b/app/assets/images/icons/butterfly.svg new file mode 100644 index 000000000..551cc7323 --- /dev/null +++ b/app/assets/images/icons/butterfly.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/cat.svg b/app/assets/images/icons/cat.svg new file mode 100644 index 000000000..14fe24a4f --- /dev/null +++ b/app/assets/images/icons/cat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/delete.svg b/app/assets/images/icons/delete.svg index 899b79b86..458ebd746 100644 --- a/app/assets/images/icons/delete.svg +++ b/app/assets/images/icons/delete.svg @@ -1,11 +1 @@ - - - - - - - - - - - + \ No newline at end of file diff --git a/app/assets/images/icons/earth-worm.svg b/app/assets/images/icons/earth-worm.svg new file mode 100644 index 000000000..e5e9b1f13 --- /dev/null +++ b/app/assets/images/icons/earth-worm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/edit.svg b/app/assets/images/icons/edit.svg new file mode 100644 index 000000000..de8a6230b --- /dev/null +++ b/app/assets/images/icons/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/finish.svg b/app/assets/images/icons/finish.svg new file mode 100644 index 000000000..37ff43b0e --- /dev/null +++ b/app/assets/images/icons/finish.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/garden.svg b/app/assets/images/icons/garden.svg deleted file mode 100644 index 11b9396f7..000000000 --- a/app/assets/images/icons/garden.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/assets/images/icons/gardener.svg b/app/assets/images/icons/gardener.svg new file mode 100644 index 000000000..3f47a2fcd --- /dev/null +++ b/app/assets/images/icons/gardener.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/gardens.svg b/app/assets/images/icons/gardens.svg new file mode 100644 index 000000000..fa71ba208 --- /dev/null +++ b/app/assets/images/icons/gardens.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/grass.svg b/app/assets/images/icons/grass.svg new file mode 100644 index 000000000..9d77d945d --- /dev/null +++ b/app/assets/images/icons/grass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/harvest-add.svg b/app/assets/images/icons/harvest-add.svg new file mode 100644 index 000000000..f40bc92bc --- /dev/null +++ b/app/assets/images/icons/harvest-add.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/assets/images/icons/harvest.svg b/app/assets/images/icons/harvest.svg index e941e9e92..8b536cc22 100644 --- a/app/assets/images/icons/harvest.svg +++ b/app/assets/images/icons/harvest.svg @@ -1,5 +1 @@ - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/icons/home.svg b/app/assets/images/icons/home.svg deleted file mode 100644 index ae5dc8d22..000000000 --- a/app/assets/images/icons/home.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/assets/images/icons/hose.svg b/app/assets/images/icons/hose.svg new file mode 100644 index 000000000..448d1cd78 --- /dev/null +++ b/app/assets/images/icons/hose.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/insect.svg b/app/assets/images/icons/insect.svg new file mode 100644 index 000000000..635b3259b --- /dev/null +++ b/app/assets/images/icons/insect.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/ladybird.svg b/app/assets/images/icons/ladybird.svg new file mode 100644 index 000000000..a580ccae1 --- /dev/null +++ b/app/assets/images/icons/ladybird.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/notification.svg b/app/assets/images/icons/notification.svg new file mode 100644 index 000000000..462ba7e9b --- /dev/null +++ b/app/assets/images/icons/notification.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/photo.svg b/app/assets/images/icons/photo.svg new file mode 100644 index 000000000..f002aa3f4 --- /dev/null +++ b/app/assets/images/icons/photo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/plant-seeds.svg b/app/assets/images/icons/plant-seeds.svg deleted file mode 100644 index 86fc2a6c7..000000000 --- a/app/assets/images/icons/plant-seeds.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/app/assets/images/icons/plant_parts/bark.svg b/app/assets/images/icons/plant_parts/bark.svg new file mode 100644 index 000000000..f1f1af1ed --- /dev/null +++ b/app/assets/images/icons/plant_parts/bark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/plant_parts/bulb.svg b/app/assets/images/icons/plant_parts/bulb.svg new file mode 100644 index 000000000..48b62c4ce --- /dev/null +++ b/app/assets/images/icons/plant_parts/bulb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/plant_parts/flower.svg b/app/assets/images/icons/plant_parts/flower.svg new file mode 100644 index 000000000..2aed72c48 --- /dev/null +++ b/app/assets/images/icons/plant_parts/flower.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/plant_parts/fruit.svg b/app/assets/images/icons/plant_parts/fruit.svg new file mode 100644 index 000000000..115ac4bcb --- /dev/null +++ b/app/assets/images/icons/plant_parts/fruit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/plant_parts/leaves.svg b/app/assets/images/icons/plant_parts/leaves.svg new file mode 100644 index 000000000..3f7da11bd --- /dev/null +++ b/app/assets/images/icons/plant_parts/leaves.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/plant_parts/pod.svg b/app/assets/images/icons/plant_parts/pod.svg new file mode 100644 index 000000000..b06004f4c --- /dev/null +++ b/app/assets/images/icons/plant_parts/pod.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/plant_parts/seeds.svg b/app/assets/images/icons/plant_parts/seeds.svg new file mode 100644 index 000000000..c8652e798 --- /dev/null +++ b/app/assets/images/icons/plant_parts/seeds.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/plant_parts/tuber.svg b/app/assets/images/icons/plant_parts/tuber.svg new file mode 100644 index 000000000..2a96312c2 --- /dev/null +++ b/app/assets/images/icons/plant_parts/tuber.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/planting-add.svg b/app/assets/images/icons/planting-add.svg new file mode 100644 index 000000000..dd025e3c6 --- /dev/null +++ b/app/assets/images/icons/planting-add.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/assets/images/icons/planting-hand.svg b/app/assets/images/icons/planting-hand.svg new file mode 100644 index 000000000..03731c9a6 --- /dev/null +++ b/app/assets/images/icons/planting-hand.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/planting-sun.svg b/app/assets/images/icons/planting-sun.svg new file mode 100644 index 000000000..4b69d1d59 --- /dev/null +++ b/app/assets/images/icons/planting-sun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/planting.svg b/app/assets/images/icons/planting.svg index 48d867aa0..bb37c3756 100644 --- a/app/assets/images/icons/planting.svg +++ b/app/assets/images/icons/planting.svg @@ -1,5 +1 @@ - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/icons/post.svg b/app/assets/images/icons/post.svg index 2e8615513..7198c4607 100644 --- a/app/assets/images/icons/post.svg +++ b/app/assets/images/icons/post.svg @@ -1,6 +1 @@ - - - - - - + \ No newline at end of file diff --git a/app/assets/images/icons/rabbit.svg b/app/assets/images/icons/rabbit.svg new file mode 100644 index 000000000..ed73bb996 --- /dev/null +++ b/app/assets/images/icons/rabbit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/seed-add.svg b/app/assets/images/icons/seed-add.svg new file mode 100644 index 000000000..9040d3628 --- /dev/null +++ b/app/assets/images/icons/seed-add.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/seeds-colour.svg b/app/assets/images/icons/seeds-colour.svg deleted file mode 100644 index b2bc3e95b..000000000 --- a/app/assets/images/icons/seeds-colour.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/assets/images/icons/seeds.svg b/app/assets/images/icons/seeds.svg index e546336af..b2bc3e95b 100644 --- a/app/assets/images/icons/seeds.svg +++ b/app/assets/images/icons/seeds.svg @@ -1,5 +1,18 @@ - + - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/images/icons/slug-eating.svg b/app/assets/images/icons/slug-eating.svg new file mode 100644 index 000000000..37779e14d --- /dev/null +++ b/app/assets/images/icons/slug-eating.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/slug.svg b/app/assets/images/icons/slug.svg new file mode 100644 index 000000000..fd1c93e6e --- /dev/null +++ b/app/assets/images/icons/slug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/snail.svg b/app/assets/images/icons/snail.svg new file mode 100644 index 000000000..bdeee93f0 --- /dev/null +++ b/app/assets/images/icons/snail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/spiderweb.svg b/app/assets/images/icons/spiderweb.svg new file mode 100644 index 000000000..634bf37ee --- /dev/null +++ b/app/assets/images/icons/spiderweb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/sprinkler.svg b/app/assets/images/icons/sprinkler.svg new file mode 100644 index 000000000..3458f029f --- /dev/null +++ b/app/assets/images/icons/sprinkler.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/sprout-add.svg b/app/assets/images/icons/sprout-add.svg new file mode 100644 index 000000000..e58159cd7 --- /dev/null +++ b/app/assets/images/icons/sprout-add.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/assets/images/icons/sprout.svg b/app/assets/images/icons/sprout.svg new file mode 100644 index 000000000..bfebc1bb5 --- /dev/null +++ b/app/assets/images/icons/sprout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/stones.svg b/app/assets/images/icons/stones.svg new file mode 100644 index 000000000..06585a21b --- /dev/null +++ b/app/assets/images/icons/stones.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/timeline.svg b/app/assets/images/icons/timeline.svg new file mode 100644 index 000000000..e1e151dda --- /dev/null +++ b/app/assets/images/icons/timeline.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/watering-can.svg b/app/assets/images/icons/watering-can.svg new file mode 100644 index 000000000..3e24501d1 --- /dev/null +++ b/app/assets/images/icons/watering-can.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/icons/wheelbarrow.svg b/app/assets/images/icons/wheelbarrow.svg new file mode 100644 index 000000000..97d319f29 --- /dev/null +++ b/app/assets/images/icons/wheelbarrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/javascripts/datepicker.js b/app/assets/javascripts/datepicker.js new file mode 100644 index 000000000..29778c169 --- /dev/null +++ b/app/assets/javascripts/datepicker.js @@ -0,0 +1,3 @@ +$(document).ready(function() { + $('.add-datepicker').datepicker({'format': 'yyyy-mm-dd'}); +}); diff --git a/app/assets/javascripts/editable.js b/app/assets/javascripts/editable.js new file mode 100644 index 000000000..e28846cd1 --- /dev/null +++ b/app/assets/javascripts/editable.js @@ -0,0 +1,6 @@ +$(document).ready(function() { + $('.editable').click(function() { + $(this.dataset.form).show(); + $(this.dataset.display).hide(); + }); +}); diff --git a/app/assets/javascripts/plantings.js.coffee b/app/assets/javascripts/plantings.js.coffee deleted file mode 100644 index ab5b73462..000000000 --- a/app/assets/javascripts/plantings.js.coffee +++ /dev/null @@ -1,6 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ - -jQuery -> - $('.add-datepicker').datepicker('format' : 'yyyy-mm-dd') diff --git a/app/assets/javascripts/seeds.js.coffee b/app/assets/javascripts/seeds.js.coffee deleted file mode 100644 index ab5b73462..000000000 --- a/app/assets/javascripts/seeds.js.coffee +++ /dev/null @@ -1,6 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ - -jQuery -> - $('.add-datepicker').datepicker('format' : 'yyyy-mm-dd') diff --git a/app/assets/stylesheets/_crops.scss b/app/assets/stylesheets/_crops.scss index 2d72137b9..4649812df 100644 --- a/app/assets/stylesheets/_crops.scss +++ b/app/assets/stylesheets/_crops.scss @@ -7,7 +7,7 @@ bottom: 0; color: $white; margin: 0; - opacity: .9; + opacity: .8; position: absolute; text-align: center; width: 100%; @@ -15,12 +15,16 @@ h3 { background-color: $brown; font-size: 1em; + margin-bottom: 0; + padding-bottom: 0; } h5.crop-sci-name { background-color: $beige; color: $black; font-size: .7em; + margin-top: 0; + padding-top: 0; } a { @@ -33,6 +37,7 @@ .img-card { border: 5%; + border-radius: 5%; } } } @@ -42,7 +47,6 @@ height: 100%; margin: .1em; min-height: 300px; - width: 100px; } .img-thumbnail { @@ -71,28 +75,18 @@ } .crop-chip { - background-color: lighten($green, 20%); - border-radius: 25px; - display: inline-block; - font-size: 1em; - height: 30px; - line-height: 30px; - margin: .2em; - padding: 0 25px; - - a { - color: $white; - } - - img { - border-radius: 50%; - float: left; - height: 30px; - margin: 0 10px 0 -25px; - width: 30px; - } + background-color: lighten($brown, 20%); } .crop-hero-photo { max-height: 300px; } + +@include media-breakpoint-down(xs) { + .index-cards { + .crop-thumbnail { + margin: .2em; + width: 30%; + } + } +} diff --git a/app/assets/stylesheets/_harvests.scss b/app/assets/stylesheets/_harvests.scss index e69de29bb..560983965 100644 --- a/app/assets/stylesheets/_harvests.scss +++ b/app/assets/stylesheets/_harvests.scss @@ -0,0 +1,34 @@ +.harvest-thumbnail { + .text { + color: $white; + margin: 0; + opacity: .9; + position: absolute; + text-align: center; + top: 50%; + width: 100%; + + h3 { + background-color: $green; + font-size: 1em; + } + + h5 { + background-color: $brown; + color: $white; + font-size: .7em; + } + + a { + color: $white; + } + + a:hover { + color: $black; + } + + .img-card { + border: 5%; + } + } +} diff --git a/app/assets/stylesheets/_members.scss b/app/assets/stylesheets/_members.scss index 1ab725311..188b4a317 100644 --- a/app/assets/stylesheets/_members.scss +++ b/app/assets/stylesheets/_members.scss @@ -19,25 +19,10 @@ .member-chip { background-color: lighten($green, 30%); - border-radius: 25px; - display: inline-block; - font-size: .8em; - height: 30px; - line-height: 30px; - padding: 0 25px; - white-space: nowrap; a { color: $black; } - - img { - border-radius: 50%; - float: left; - height: 30px; - margin: 0 10px 0 -25px; - width: 30px; - } } .member-location { diff --git a/app/assets/stylesheets/_seeds.scss b/app/assets/stylesheets/_seeds.scss index e69de29bb..e875832ff 100644 --- a/app/assets/stylesheets/_seeds.scss +++ b/app/assets/stylesheets/_seeds.scss @@ -0,0 +1,10 @@ +.seed-card { + .text { + color: $white; + margin: 0; + position: absolute; + text-align: center; + top: 1em; + width: 100%; + } +} diff --git a/app/assets/stylesheets/_variables.scss b/app/assets/stylesheets/_variables.scss index 5d9bdda5b..0f46481a7 100644 --- a/app/assets/stylesheets/_variables.scss +++ b/app/assets/stylesheets/_variables.scss @@ -14,7 +14,8 @@ $white: #fff; $body-bg: $beige; $text-color: $brown; $link-color: $green; -$graph-hover: $orange; + +$default-font: "Fira Sans", Helvetica, Arial, sans-serif; $primary: ( color: $green, diff --git a/app/assets/stylesheets/overrides.scss b/app/assets/stylesheets/overrides.scss index df44ca6e8..f9d965fec 100755 --- a/app/assets/stylesheets/overrides.scss +++ b/app/assets/stylesheets/overrides.scss @@ -5,7 +5,7 @@ body { body { background-color: $beige; - font-family: $font-family-sans-serif; + font-family: $default-font; } .ellipsis { @@ -29,7 +29,7 @@ a:hover { } h1 { - font-size: 180%; + font-size: 250%; } h2 { @@ -59,6 +59,7 @@ section { h2 { background-color: $green; + box-shadow: 1px 1px 1px 1px darken($beige, 20%); color: $white; padding: .2em; @@ -68,7 +69,11 @@ section { } .btn { - border: 1px solid $green; + border: 1px solid $brown; + } + + .card { + box-shadow: 1px 3px 3px 1px darken($beige, 20%); } } @@ -84,7 +89,6 @@ section { .card { background: $white; - // border: 1px solid lighten($brown, 20%); border-radius: 5%; margin: .5em .5em .5em 0; width: 200px; @@ -94,6 +98,12 @@ section { border-top-right-radius: 5%; } } + .card-finished { + background: darken($beige, 10%); + a { + color: $brown; + } + } .card:hover { background-color: $beige; @@ -104,7 +114,7 @@ section { margin-bottom: 1em; .img-card { - height: 180px; + height: 200px; object-fit: cover; width: 100%; } @@ -143,6 +153,17 @@ section { } } +img.img-cute { + bottom: -6px; + left: 45px; + position: relative; + width: 3em; +} + +img.img-tiny { + width: 50px; +} + img.img-icon { width: 1.2em; } @@ -158,16 +179,8 @@ img.avatar { z-index: 2; } -.progress { - border-radius: 0; - height: 2em; - .progress-bar { - height: 2em; - background-color: $progress-bar-color - } - .progress-bar-text { - text-align: center; - } +.progress-bar { + border-bottom: 1em solid $progress-bar-color; } ul.associations { @@ -312,6 +325,29 @@ ul.thumbnail-buttons { background-color: $beige; } +.chip { + background-color: lighten($brown, 20%); + border-radius: 25px; + color: $white; + display: inline-block; + height: 30px; + line-height: 30px; + margin: .2em; + padding: 0 25px; + + a { + color: $white; + } + + img { + border-radius: 50%; + float: left; + height: 30px; + margin: 0 10px 0 -25px; + width: 30px; + } +} + // Overrides applying only to mobile view. This must be at the end of the overrides file. // Extra small devices (portrait phones, less than 576px) @include media-breakpoint-down(xs) { @@ -371,7 +407,7 @@ ul.thumbnail-buttons { .index-cards { .card { margin: .2em; - width: 45%; + width: 48%; // Shrink title to fit more on page .card-title { diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 65a559423..4d563ca4c 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -113,7 +113,10 @@ class CropsController < ApplicationController recreate_names('alt_name', 'alternate') recreate_names('sci_name', 'scientific') - notifier.deliver_now! if @crop.approval_status_changed?(from: "pending", to: "approved") + if @crop.approval_status_changed?(from: "pending", to: "approved") + notifier.deliver_now! + @crop.update_openfarm_data! + end else @crop.approval_status = @crop.approval_status_was end @@ -210,7 +213,7 @@ class CropsController < ApplicationController q = Crop.approved.includes(:scientific_names, plantings: :photos) q = q.popular unless @sort == 'alpha' q.order(Arel.sql("LOWER(crops.name)")) - .includes(:photos).paginate(page: params[:page], per_page: 30) + .includes(:photos).paginate(page: params[:page]) end def requested_crops diff --git a/app/controllers/gardens_controller.rb b/app/controllers/gardens_controller.rb index f9037923a..4fff56da5 100644 --- a/app/controllers/gardens_controller.rb +++ b/app/controllers/gardens_controller.rb @@ -5,20 +5,17 @@ class GardensController < ApplicationController responders :flash respond_to :html, :json - # GET /gardens - # GET /gardens.json def index @owner = Member.find_by(slug: params[:member_slug]) @show_all = params[:all] == '1' @gardens = @gardens.active unless @show_all @gardens = @gardens.where(owner: @owner) if @owner.present? - @gardens = @gardens.joins(:owner).order(:name).paginate(page: params[:page]) + @gardens = @gardens.where.not(members: { confirmed_at: nil }) + .order(:name).paginate(page: params[:page]) respond_with(@gardens) end - # GET /gardens/1 - # GET /gardens/1.json def show @current_plantings = @garden.plantings.current .includes(:crop, :owner) @@ -29,35 +26,26 @@ class GardensController < ApplicationController respond_with(@garden) end - # GET /gardens/new - # GET /gardens/new.json def new @garden = Garden.new respond_with(@garden) end - # GET /gardens/1/edit def edit respond_with(@garden) end - # POST /gardens - # POST /gardens.json def create @garden.owner_id = current_member.id flash[:notice] = I18n.t('gardens.created') if @garden.save respond_with(@garden) end - # PUT /gardens/1 - # PUT /gardens/1.json def update flash[:notice] = I18n.t('gardens.updated') if @garden.update(garden_params) respond_with(@garden) end - # DELETE /gardens/1 - # DELETE /gardens/1.json def destroy @garden.destroy flash[:notice] = I18n.t('gardens.deleted') diff --git a/app/controllers/harvests_controller.rb b/app/controllers/harvests_controller.rb index f1c98fe86..353e338d6 100644 --- a/app/controllers/harvests_controller.rb +++ b/app/controllers/harvests_controller.rb @@ -43,7 +43,11 @@ class HarvestsController < ApplicationController @harvest.crop_id = @harvest.planting.crop_id if @harvest.planting_id @harvest.harvested_at = Time.zone.now if @harvest.harvested_at.blank? @harvest.save - respond_with(@harvest) + if params[:return] == 'planting' + respond_with(@harvest, location: @harvest.planting) + else + respond_with(@harvest) + end end def update diff --git a/app/controllers/plantings_controller.rb b/app/controllers/plantings_controller.rb index 1bbbefc93..09004b823 100644 --- a/app/controllers/plantings_controller.rb +++ b/app/controllers/plantings_controller.rb @@ -61,6 +61,7 @@ class PlantingsController < ApplicationController def create @planting = Planting.new(planting_params) + @planting.planted_at = Time.zone.now if @planting.planted_at.blank? @planting.owner = current_member @planting.crop = @planting.parent_seed.crop if @planting.parent_seed.present? @planting.save diff --git a/app/controllers/seeds_controller.rb b/app/controllers/seeds_controller.rb index 1989db825..207b8d639 100644 --- a/app/controllers/seeds_controller.rb +++ b/app/controllers/seeds_controller.rb @@ -6,19 +6,15 @@ class SeedsController < ApplicationController respond_to :csv, only: :index respond_to :rss, only: :index - # GET /seeds - # GET /seeds.json def index @owner = Member.find_by(slug: params[:member_slug]) if params[:member_slug].present? @crop = Crop.find_by(slug: params[:crop_slug]) if params[:crop_slug].present? @planting = Planting.find_by(slug: params[:planting_id]) if params[:planting_id].present? - @seeds = @seeds.where(owner: @owner) if @owner.present? - @seeds = @seeds.where(crop: @crop) if @crop.present? - @seeds = @seeds.where(parent_planting: @planting) if @planting.present? - @seeds = @seeds.order(created_at: :desc).includes(:owner, :crop).paginate(page: params[:page]) + @show_all = (params[:all] == '1') @filename = csv_filename + @seeds = seeds.order(created_at: :desc).includes(:owner, :crop).paginate(page: params[:page]) respond_with(@seeds) end @@ -46,7 +42,11 @@ class SeedsController < ApplicationController @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) + if params[:return] == 'planting' + respond_with(@seed, location: @seed.parent_planting) + else + respond_with(@seed) + end end def update @@ -61,6 +61,15 @@ class SeedsController < ApplicationController private + def seeds + records = Seed.all + records = records.where(owner: @owner) if @owner.present? + records = records.where(crop: @crop) if @crop.present? + records = records.where(parent_planting: @planting) if @planting.present? + records = records.active unless @show_all + records + end + def seed_params params.require(:seed).permit( :crop_id, :description, :quantity, :plant_before, diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 29f0ab05b..68ee9c7d8 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -63,15 +63,15 @@ module ApplicationHelper pluralize(collection.size, model.model_name.to_s.downcase) end - def show_inactive_tickbox_path(type, owner, show_all) + def show_inactive_tickbox_path(type, owner: nil, show_all: false) all = show_all ? '' : 1 - if owner - return member_plantings_path(owner, all: all) if type == 'plantings' - return member_gardens_path(owner, all: all) if type == 'gardens' - end - return plantings_path(all: all) if type == 'plantings' - return gardens_path(all: all) if type == 'gardens' + path = if owner.present? + public_send("member_#{type}_path", owner, all: all) + else + public_send("#{type}_path", all: all) + end + path end def title(type, owner, crop, planting) diff --git a/app/helpers/buttons_helper.rb b/app/helpers/buttons_helper.rb index cbcab26a3..05fc2798d 100644 --- a/app/helpers/buttons_helper.rb +++ b/app/helpers/buttons_helper.rb @@ -107,7 +107,7 @@ module ButtonsHelper link_to new_photo_path(id: model.id, type: model_type_for_photo(model)), class: classes do - photo_icon + ' ' + t('buttons.add_photo') + add_photo_icon + ' ' + t('buttons.add_photo') end end diff --git a/app/helpers/editable_form_helper.rb b/app/helpers/editable_form_helper.rb new file mode 100644 index 000000000..00cabebad --- /dev/null +++ b/app/helpers/editable_form_helper.rb @@ -0,0 +1,6 @@ +module EditableFormHelper + def editable(field_type, model, field, display_field:, collection: []) + render 'shared/editable/form', field_type: field_type, + model: model, field: field, display_field: display_field, collection: collection + end +end diff --git a/app/helpers/gardens_helper.rb b/app/helpers/gardens_helper.rb index fd406431e..1ebb589f0 100644 --- a/app/helpers/gardens_helper.rb +++ b/app/helpers/gardens_helper.rb @@ -9,10 +9,6 @@ module GardensHelper end end - def gardens_active_tickbox_path(owner, show_all) - show_inactive_tickbox_path('gardens', owner, show_all) - end - def display_garden_name(garden) truncate(garden.name, length: 50, separator: ' ', omission: '... ') end diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index b21cf0757..d5839ed05 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -5,12 +5,20 @@ module IconsHelper send("#{event_model}_icon") end + def cute_icon + icons = %w(slug sprinkler bee ant hose grass rabbit slug-eating snail earth-worm insect watering-can + wheelbarrow cat spiderweb bug butterfly ladybird stones) + rand_num = rand(1..icons.size) + icon = icons[rand_num - 1] + image_tag("icons/#{icon}.svg", class: 'img img-cute', alt: icon) + end + def timeline_icon - icon('far', 'calendar') + image_icon 'timeline' end def garden_icon - image_icon 'home' + image_icon 'gardens' end def planting_icon @@ -34,19 +42,23 @@ module IconsHelper end def finished_icon - icon('fas', 'calendar') + image_icon 'finish' end def edit_icon - icon('fas', 'edit') + image_icon 'edit' end def delete_icon - icon('fas', 'trash-alt') + image_icon 'delete' + end + + def add_photo_icon + image_icon 'add-photo' end def photo_icon - icon('fas', 'camera-retro') + image_icon 'photo' end def seedling_icon @@ -84,10 +96,15 @@ module IconsHelper end def sunniness_icon(sunniness) - if sunniness.present? - image_tag("sunniness_#{sunniness}.png", class: 'img', alt: sunniness, width: 55) + case sunniness + when 'sun' + icon 'far', 'sun' + when 'shade' + icon 'fas', 'umbrella-beach' + when 'semi-shade' + icon 'fas', 'cloud-sun' else - image_tag("sunniness_not_specified.png", class: 'img', alt: 'unknown', width: 55) + icon 'fas', 'question' end end diff --git a/app/helpers/plantings_helper.rb b/app/helpers/plantings_helper.rb index 537ae7631..2c28eda76 100644 --- a/app/helpers/plantings_helper.rb +++ b/app/helpers/plantings_helper.rb @@ -29,8 +29,8 @@ module PlantingsHelper end end - def plantings_active_tickbox_path(owner, show_all) - show_inactive_tickbox_path('plantings', owner, show_all) + def weeks_from_not_to_finished(planting) + days_from_now_to_finished(planting) / 7 end def days_from_now_to_finished(planting) @@ -45,6 +45,10 @@ module PlantingsHelper (planting.first_harvest_predicted_at - Time.zone.today).to_i end + def weeks_from_now_to_first_harvest(planting) + days_from_now_to_first_harvest(planting) / 7 + end + def days_from_now_to_last_harvest(planting) return unless planting.planted_at.present? && planting.last_harvest_predicted_at.present? diff --git a/app/models/concerns/predict_planting.rb b/app/models/concerns/predict_planting.rb index 8b2961f64..052f7ed55 100644 --- a/app/models/concerns/predict_planting.rb +++ b/app/models/concerns/predict_planting.rb @@ -41,6 +41,10 @@ module PredictPlanting (Time.zone.today - planted_at).to_i if planted_at.present? end + def weeks_since_planted + days_since_planted / 7 + end + # progress def percentage_grown if finished? diff --git a/app/models/crop.rb b/app/models/crop.rb index a9dfabe52..d0283a2b6 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -10,7 +10,6 @@ class Crop < ApplicationRecord belongs_to :requester, class_name: 'Member', optional: true, inverse_of: :requested_crops belongs_to :parent, class_name: 'Crop', optional: true, inverse_of: :varieties has_many :scientific_names, dependent: :delete_all - accepts_nested_attributes_for :scientific_names, allow_destroy: true, reject_if: :all_blank has_many :alternate_names, dependent: :delete_all has_many :plantings, dependent: :destroy has_many :seeds, dependent: :destroy @@ -24,6 +23,8 @@ class Crop < ApplicationRecord has_many :crop_posts, dependent: :delete_all has_many :posts, through: :crop_posts, dependent: :delete_all + accepts_nested_attributes_for :scientific_names, allow_destroy: true, reject_if: :all_blank + ## ## Scopes scope :recent, -> { approved.order(created_at: :desc) } @@ -95,6 +96,10 @@ class Crop < ApplicationRecord .count("harvests.id") end + def perennial? + perennial == true + end + def annual? perennial == false end diff --git a/app/models/harvest.rb b/app/models/harvest.rb index 8a78ad4fc..36f61965f 100644 --- a/app/models/harvest.rb +++ b/app/models/harvest.rb @@ -111,15 +111,11 @@ class Harvest < ApplicationRecord end def unit_to_human - return "" unless quantity + return "" unless quantity && unit + return 'individual' if unit == 'individual' + return "#{unit} of" if quantity == 1 - if unit == 'individual' - 'individual' - elsif quantity == 1 - "#{unit} of" - else - "#{unit.pluralize} of" - end + "#{unit.pluralize} of" end def weight_to_human diff --git a/app/models/photo.rb b/app/models/photo.rb index a1e7099c1..1490c33dc 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -7,8 +7,8 @@ class Photo < ApplicationRecord has_many :photo_associations, foreign_key: :photo_id, dependent: :delete_all, inverse_of: :photo has_many :crops, through: :photo_associations - validates :fullsize_url, url: true, uniqueness: true - validates :thumbnail_url, url: true, uniqueness: true + validates :fullsize_url, url: true + validates :thumbnail_url, url: true # creates a relationship for each assignee type PHOTO_CAPABLE.each do |type| diff --git a/app/models/planting.rb b/app/models/planting.rb index 0555e4ac5..868f36735 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -33,6 +33,8 @@ class Planting < ApplicationRecord ## ## Scopes scope :active, -> { where('finished <> true').where('finished_at IS NULL OR finished_at < ?', Time.zone.now) } + scope :annual, -> { joins(:crop).where(crops: { perennial: false }) } + scope :perennial, -> { joins(:crop).where(crops: { perennial: true }) } scope :interesting, -> { has_photos.one_per_owner.order(planted_at: :desc) } scope :recent, -> { order(created_at: :desc) } scope :one_per_owner, lambda { diff --git a/app/models/seed.rb b/app/models/seed.rb index 8e0544b52..32c0ef6a5 100644 --- a/app/models/seed.rb +++ b/app/models/seed.rb @@ -53,7 +53,7 @@ class Seed < ApplicationRecord scope :interesting, -> { tradable.has_location } scope :has_location, -> { joins(:owner).where.not("members.location": nil) } scope :recent, -> { order(created_at: :desc) } - scope :active, -> { where('finished_at < ?', Time.zone.now) } + scope :active, -> { where('finished <> true').where('finished_at IS NULL OR finished_at < ?', Time.zone.now) } def tradable? tradable_to != 'nowhere' diff --git a/app/views/crops/_actions.html.haml b/app/views/crops/_actions.html.haml index 1fd159662..835edea1c 100644 --- a/app/views/crops/_actions.html.haml +++ b/app/views/crops/_actions.html.haml @@ -1,16 +1,22 @@ -- if @crop.approved? && signed_in? - .nav.crop-actions - - if can? :create, Planting - = link_to new_planting_path(crop_id: crop.id), class: 'list-group-item btn' do - = planting_icon - = t('buttons.plant_crop', crop_name: crop.name) - - - if can? :create, Harvest - = link_to new_harvest_path(crop_id: crop.id), class: 'list-group-item btn' do - = harvest_icon - = t('buttons.harvest_crop', crop_name: crop.name) - - - if can? :create, Seed - = link_to new_seed_path(crop_id: crop.id), class: 'list-group-item btn' do - = seed_icon - = t('buttons.add_seed_to_stash', crop_name: crop.name) +- if crop.approved? && signed_in? + %ul.nav.crop-actions + %li.nav-item.dropdown.btn.btn-sm + %a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", role: "button", href: '#'} Add to garden + .dropdown-menu.dropdown-secondary + - current_member.gardens.active.each do |garden| + = link_to plantings_path(planting: {crop_id: crop.id, garden_id: garden.id}), method: :post, class: 'dropdown-item' do + = garden.name + .dropdown-divider + = link_to 'add new garden', new_garden_path, class: 'dropdown-item' + %li.nav-item.dropdown.btn.btn-sm + %a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", role: "button", href: '#'} Record harvest + .dropdown-menu.dropdown-secondary + - PlantPart.all.each do |plant_part| + = link_to harvests_path(harvest: {crop_id: crop.id, plant_part_id: plant_part.id}), method: :post, class: 'dropdown-item' do + = plant_part.name + %li.nav-item.dropdown.btn.btn-sm + %a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", role: "button", href: '#'}=t('buttons.save_seeds', crop_name: crop.name) + .dropdown-menu.dropdown-secondary + - Seed::TRADABLE_TO_VALUES.each do |trade| + = link_to seeds_path(seed: {crop_id: crop.id, tradable_to: trade}), method: :post, class: 'dropdown-item' do + Will trade: #{trade} diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index a0f981959..2ef58f243 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -41,6 +41,8 @@ = f.radio_button(:perennial, true, label: "Perennial") %span.help-block Living more than two years + - unless @crop.approved? + = link_to 'Search wikipedia', "https://en.wikipedia.org/w/index.php?search=#{@crop.name}", target: '_blank' = f.text_field :en_wikipedia_url, id: "en_wikipedia_url", label: 'Wikipedia URL' %span.help-block Link to the crop's page on the English language Wikipedia (required). diff --git a/app/views/crops/_hierarchy.html.haml b/app/views/crops/_hierarchy.html.haml index 989c5145b..2e8af76c3 100644 --- a/app/views/crops/_hierarchy.html.haml +++ b/app/views/crops/_hierarchy.html.haml @@ -5,6 +5,8 @@ - display_crops.each do |c| %li.crop-hierarchy{ class: (max != 0 && @count >= max) || !c.approved? ? ['hide', 'toggle'] : [] } = render 'crops/tiny', crop: c + - if c.perennial + = perennial_icon - @count += 1 - if c.varieties.present? - c.varieties.order(:name).each do |v| diff --git a/app/views/crops/_info.haml b/app/views/crops/_info.haml index efaf693cc..2e4266dc6 100644 --- a/app/views/crops/_info.haml +++ b/app/views/crops/_info.haml @@ -1,15 +1,18 @@ .row .col-md-9 - %h1 + %h1.display-3 = crop_icon(@crop) %strong= @crop.name.titleize - unless @crop.approved? %badge.badge-warning=@crop.approval_status %small.text-muted= @crop.default_scientific_name - if @crop.sowing_method.present? - %h2= @crop.sowing_method + %h2 + How to sow #{@crop.name}: + = @crop.sowing_method - if @crop.sun_requirements.present? %p + %strong Sun requirement for #{@crop}: Plant in #{@crop.sun_requirements} %p.text-muted - if !@crop.plantings.empty? diff --git a/app/views/crops/_posts.html.haml b/app/views/crops/_posts.html.haml index 1fcfea2fc..1ce1bc7ff 100644 --- a/app/views/crops/_posts.html.haml +++ b/app/views/crops/_posts.html.haml @@ -12,11 +12,11 @@ locals: { to: "post your tips and experiences growing #{crop.name.pluralize}" } - else - = render 'layouts/pagination', collection: @posts + = will_paginate @posts .index-cards - @posts.each do |post| = render 'posts/preview', post: post - = render 'layouts/pagination', collection: @posts + = will_paginate @posts diff --git a/app/views/crops/_predictions.html.haml b/app/views/crops/_predictions.html.haml index 02e3bbacc..456756fe4 100644 --- a/app/views/crops/_predictions.html.haml +++ b/app/views/crops/_predictions.html.haml @@ -6,19 +6,23 @@ .card.fact-card .card-body.text-center %h3 - = link_to 'https://en.wikipedia.org/wiki/Annual_vs._perennial_plant_evolution' do - - if crop.perennial == true + = link_to 'https://en.wikipedia.org/wiki/Annual_vs._perennial_plant_evolution', class: 'crop-longevity' do + - if crop.perennial? Perennial - - elsif crop.perennial == false + - elsif crop.annual? Annual - - %strong + %strong.crop-longevity %i.far.fa-calendar - if crop.perennial == true %small living more than two years - elsif crop.perennial == false %small living and reproducing in a single year or less + - if can? :wrangle, @crop + %small.edit-link + = bootstrap_form_for(@crop) do |f| + = f.hidden_field :perennial, value: crop.annual? + = f.submit :toggle - if crop.annual? && crop.median_lifespan.present? .card.fact-card @@ -28,7 +32,6 @@ %i.fas.fa-sun-o.fa-5x.pt-3.amber-text %span days - - if crop.median_days_to_first_harvest.present? .card.fact-card .card-body.text-center diff --git a/app/views/crops/_tiny.html.haml b/app/views/crops/_tiny.html.haml index 8b948a9cc..512379059 100644 --- a/app/views/crops/_tiny.html.haml +++ b/app/views/crops/_tiny.html.haml @@ -1,7 +1,7 @@ - if crop.approved? || can?(:wrangle, Crop) - .crop-chip - = link_to crop do + = link_to crop do + %span.chip.crop-chip = crop_icon(crop) = crop.name - - unless crop.approved? - %badge.badge-warning= crop.approval_status + - unless crop.approved? + %badge.badge-warning= crop.approval_status diff --git a/app/views/crops/index.html.haml b/app/views/crops/index.html.haml index 07e0d37b7..7fc088750 100644 --- a/app/views/crops/index.html.haml +++ b/app/views/crops/index.html.haml @@ -9,29 +9,23 @@ - content_for :breadcrumbs do %li.breadcrumb-item.active= link_to 'Crops', crops_path -%h1=t('.title') -%p - #{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where. - View any crop page to see which of our members have planted it and find - information on how to grow it yourself. - - = bootstrap_form_tag(url: crops_path, method: :get, layout: :inline) do |f| - = f.select "sort", - options_for_select({ "popularity": 'popular', - "alphabetically": 'alpha' }, - @sort || 'popular'), - label: 'Sort by' - = f.submit "Show" + .input-group + = f.select "sort", + options_for_select({ "popularity": 'popular', + "alphabetically": 'alpha' }, + @sort || 'popular'), + label: 'Sort by' + = f.submit "Show" -= render 'layouts/pagination', collection: @crops - -.crops +%section.crops + %h2= t('.title') + = will_paginate @crops .index-cards - @crops.each do |crop| = render 'crops/thumbnail', crop: crop -= render 'layouts/pagination', collection: @crops + = will_paginate @crops %ul.list-inline %li The data on this page is available in the following formats: diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index bb4a25287..cc9b680fe 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -17,34 +17,38 @@ .jumbotron= render 'crops/info' .row - .col-md-9 - %p= render 'crops/actions', crop: @crop - .col-md-3 - = render 'wrangle', crop: @crop + .col-md-9= render 'crops/actions', crop: @crop + .col-md-3= render 'wrangle', crop: @crop .row .col-md-9 - %section.prediction= render 'predictions', crop: @crop + %section.prediction + = cute_icon + = render 'predictions', crop: @crop - if @crop.companions.any? %section.companions %h2 Companions - @crop.companions.each do |companion| = render 'crops/tiny', crop: companion - %section.photos= render 'crops/photos', photos: @photos, crop: @crop + %section.photos + = cute_icon + = render 'crops/photos', photos: @photos, crop: @crop - if @crop.plantings.any? - .card-deck.text-center - .col-md-4 - %h3.section-heading.h3.pt-4 Sunniness - = pie_chart crop_sunniness_path(@crop, format: :json), legend: "bottom" - .col-md-4 - %h3.section-heading.h3.pt-4 Planted from - = pie_chart crop_planted_from_path(@crop, format: :json), legend: "bottom" - .col-md-4 - %h3.section-heading.h3.pt-4 Harvested for - = pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom" + %section.charts + .row + .col-lg-4.col-12 + %h2 Sunniness + = pie_chart crop_sunniness_path(@crop, format: :json), legend: "bottom" + .col-lg-4.col-12 + %h2 Planted from + = pie_chart crop_planted_from_path(@crop, format: :json), legend: "bottom" + .col-lg-4.col-12 + %h2 Harvested for + = pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom" - %section.varieties= render 'varieties', crop: @crop + %section.varieties + = render 'varieties', crop: @crop %section.crop-map %h2 @@ -59,6 +63,7 @@ %section.posts= render 'crops/posts', crop: @crop .col-md-3 + = cute_icon .card .card-body %h4 How to grow #{@crop.name.pluralize} @@ -101,6 +106,7 @@ = render 'harvests', crop: @crop = render 'find_seeds', crop: @crop + = cute_icon .card .card-body %h5.card-title Learn more about #{@crop.name.pluralize} diff --git a/app/views/gardens/index.html.haml b/app/views/gardens/index.html.haml index ce0d67833..d4fba0eae 100644 --- a/app/views/gardens/index.html.haml +++ b/app/views/gardens/index.html.haml @@ -13,7 +13,7 @@ %li.breadcrumb-item.active= link_to 'Gardens', gardens_path %section.border-top - = link_to gardens_active_tickbox_path(@owner, @show_all), class: 'btn' do + = link_to show_inactive_tickbox_path('gardens', owner: @owner, show_all: @show_all), class: 'btn' do = check_box_tag 'active', 'all', @show_all include in-active @@ -25,17 +25,31 @@ - else = page_entries_info @gardens = will_paginate @gardens - - @gardens.each do |garden| - %section - %h2 - = link_to garden.name, garden - = render 'gardens/actions', garden: garden - - if garden.plantings.any? - .index-cards - - garden.plantings.active.each do |planting| - = render planting, full: true - - else - No plantings + .row + - @gardens.each do |garden| + .col-md-6.col-12 + %section.card + %h2= link_to garden.name, garden + .card-header + .row + - unless @owner.present? + .col + owner: + = render 'members/tiny', member: garden.owner + .col= render 'gardens/actions', garden: garden + .col + - if garden.plantings.any? + - if garden.plantings.active.perennial.any? + %strong Perennials: + - garden.plantings.active.perennial.each do |planting| + = link_to planting do + = crop_icon planting.crop + = planting.crop + .card-body + - if garden.plantings.active.annual.any? + = render 'plantings/progress_list', plantings: garden.plantings.active.annual + - else + No annual plantings .row .col-12= page_entries_info @gardens diff --git a/app/views/gardens/show.html.haml b/app/views/gardens/show.html.haml index 9384e088a..8c0aa69d3 100644 --- a/app/views/gardens/show.html.haml +++ b/app/views/gardens/show.html.haml @@ -10,20 +10,16 @@ = tag("meta", property: "og:url", content: request.original_url) = tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME']) -- content_for :scripts do - = javascript_include_tag "charts" - = javascript_include_tag "https://www.gstatic.com/charts/loader.js" - - - content_for :breadcrumbs do %li.breadcrumb-item= link_to 'Gardens', gardens_path %li.breadcrumb-item.active= link_to @garden.name, gardens_path(@garden) .row - .col-md-9.col-sm-12 + .col-md-9.col-12 %h2.h1 %strong= @garden - = render 'gardens/actions', garden: @garden + .col-md-3.col-12 + = render 'gardens/actions', garden: @garden .row .col-md-9 - unless @garden.active @@ -32,7 +28,6 @@ - if can? :edit, @garden = link_to 'Set it to active', edit_garden_path(@garden) to plant something in this garden. - %div %p :growstuff_markdown @@ -47,11 +42,10 @@ = link_to 'tell us more.', edit_garden_path(@garden) - if @garden.plantings.where.not(planted_at: nil).any? - .row - .col-md-12 - %section - %h2 Garden timeline - = timeline garden_timeline_path(@garden), adapter: "google" + %section.card + %h2 Garden progress + .card-body + = render 'plantings/progress_list', plantings: @garden.plantings.active %section %h2 Current plantings in garden @@ -67,7 +61,7 @@ .index-cards - if @finished_plantings.size.positive? - @finished_plantings.each do |planting| - = render "plantings/thumbnail", planting: planting + = render "plantings/tiny", planting: planting - else .col-md-12 %p Nothing has been planted here. diff --git a/app/views/harvests/_card.html.haml b/app/views/harvests/_card.html.haml index 51d077338..53ddcc3d0 100644 --- a/app/views/harvests/_card.html.haml +++ b/app/views/harvests/_card.html.haml @@ -6,7 +6,7 @@ = crop_icon(harvest.crop) %strong = link_to harvest.crop, harvest - %span.badge.badge-pill= link_to harvest.plant_part, harvest.plant_part + %span.badge.badge-pill= harvest.plant_part - if harvest.planting.present? %p.card-text %small.text-muted diff --git a/app/views/harvests/_thumbnail.html.haml b/app/views/harvests/_thumbnail.html.haml index f29828b4f..8539d72d8 100644 --- a/app/views/harvests/_thumbnail.html.haml +++ b/app/views/harvests/_thumbnail.html.haml @@ -1,10 +1,9 @@ -.thumbnail - .harvest-thumbnail - - if harvest - = link_to image_tag(harvest_image_path(harvest), - alt: harvest.crop.name, class: 'img'), - harvest - .harvestinfo - .harvest-name - = link_to display_quantity(harvest), harvest - = I18n.l(harvest.harvested_at.to_date) +.card.harvest-thumbnail + = link_to image_tag(harvest_image_path(harvest), + alt: harvest, + class: 'img img-card'), + harvest + + .text + %h3.harvest-plant-part= link_to harvest.plant_part, harvest + %h5.harvest-crop= harvest.crop diff --git a/app/views/harvests/index.html.haml b/app/views/harvests/index.html.haml index 527ce0e56..dd0ccfc29 100644 --- a/app/views/harvests/index.html.haml +++ b/app/views/harvests/index.html.haml @@ -29,7 +29,6 @@ .index-cards=render @harvests, full: true .pagination - = page_entries_info @harvests = will_paginate @harvests %section.open-data diff --git a/app/views/harvests/show.html.haml b/app/views/harvests/show.html.haml index cc68a79bd..b5f98b55e 100644 --- a/app/views/harvests/show.html.haml +++ b/app/views/harvests/show.html.haml @@ -13,43 +13,55 @@ %li.breadcrumb-item= link_to @harvest.owner, member_harvests_path(@harvest.owner) %li.breadcrumb-item.active= link_to @harvest, @harvest -.row - .col-md-8 - %h1 - = harvest_icon - #{@harvest.crop} harvested by #{@harvest.owner} - = render 'harvests/actions', harvest: @harvest - = render partial: 'planting' - .index-cards.facts - - if @harvest.plant_part +.harvest + .row + .col-md-8.col-xs-12 + %h1 + = harvest_icon + #{@harvest.crop} harvested by #{@harvest.owner} + .col-md-4.col-xs-12 + = render 'harvests/actions', harvest: @harvest + .col-md-8.col-xs-12 + = render partial: 'planting' + .index-cards.facts + - if @harvest.plant_part + .card + %h3 + Plant part + = editable :select, @harvest, :plant_part_id, collection: PlantPart.all.pluck(:name, :id), display_field: '.harvest-plantpart' + %strong.harvest-plantpart= @harvest.plant_part .card - %h3 Plant part - %span= link_to @harvest.plant_part, @harvest.plant_part - - if @harvest.harvested_at.present? + %h3 + Harvested + = editable :date, @harvest, :harvested_at, display_field: '.harvested_at' + %strong.harvested_at #{time_ago_in_words @harvest.harvested_at} ago + %span.harvested_at= I18n.l @harvest.harvested_at + + .card{class: @harvest.quantity.present? ? '' : 'text-muted'} + %h3 + Quantity + = editable :text_field, @harvest, :quantity, display_field: '.quantity' + %strong.quantity + = display_quantity(@harvest) + + - if @harvest.photos.size.positive? + %section + %h2 Photos + = render 'photos/gallery', photos: @harvest.photos.order(date_taken: :desc).limit(3) + %section.harvest-detail + %h2 Detail + - if @harvest.planting.present? + Havested from + = link_to @harvest.planting, @harvest.planting + + - if @harvest.description.present? .card - %h3 Harvested - %strong= I18n.l @harvest.harvested_at - .card - %h3 Quantity - %strong= display_quantity(@harvest) - - if @harvest.photos.size.positive? - %section - %h2 Photos - = render 'photos/gallery', photos: @harvest.photos.order(date_taken: :desc).limit(3) - %section.harvest-detail - %h2 Detail - - if @harvest.planting.present? - Havested from - = link_to @harvest.planting, @harvest.planting + .card-header + %h2 Notes + .card-body + :growstuff_markdown + #{strip_tags(@harvest.description)} - - if @harvest.description.present? - .card - .card-header - %h2 Notes - .card-body - :growstuff_markdown - #{strip_tags(@harvest.description)} - - .col-md-4 - = render 'harvests/owner', harvest: @harvest - = render @harvest.crop + .col-md-4.col-xs-12 + = render 'harvests/owner', harvest: @harvest + = render @harvest.crop diff --git a/app/views/home/_blurb.html.haml b/app/views/home/_blurb.html.haml index 11582e8b6..e65a1c396 100644 --- a/app/views/home/_blurb.html.haml +++ b/app/views/home/_blurb.html.haml @@ -1,6 +1,6 @@ .row .col-md-8.info - %h1.display-1= ENV['GROWSTUFF_SITE_NAME'] + %h1.display-3= ENV['GROWSTUFF_SITE_NAME'] %p= t('.intro', site_name: ENV['GROWSTUFF_SITE_NAME']) = render 'stats' .col-md-4 diff --git a/app/views/home/_crops.html.haml b/app/views/home/_crops.html.haml index 9a6d9d658..b463948c8 100644 --- a/app/views/home/_crops.html.haml +++ b/app/views/home/_crops.html.haml @@ -1,5 +1,5 @@ - cache cache_key_for(Crop, 'homepage'), expires_in: 1.day do .index-cards - - Crop.interesting.includes(:scientific_names, :photos).shuffle.first(12).each do |crop| + - Crop.interesting.includes(:scientific_names, :photos).shuffle.first(18).each do |crop| = render 'crops/thumbnail', crop: crop diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 3b027c956..e5caaeab3 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -2,16 +2,23 @@ = ENV['GROWSTUFF_SITE_NAME'] - if member_signed_in? - %h1.display-2= t('.welcome', site_name: ENV['GROWSTUFF_SITE_NAME'], member_name: current_member) + .row + .col-lg-8.col-md-12 + %h1.display-4= t('.welcome', site_name: ENV['GROWSTUFF_SITE_NAME'], member_name: current_member) - %p= render 'stats' + %p= render 'stats' + .col + %p + = link_to member_gardens_path(current_member), class: 'btn btn-dark' do + = image_icon 'gardens' + Show me my garden - else .hidden-xs %section.jumbotron= render 'blurb' - .row .col-lg-8.col-md-12 %section.crops + = cute_icon %h2= t('home.crops.our_crops') = render 'crops' = link_to "#{t('home.crops.view_all')} »", crops_path, class: 'btn btn-block' @@ -23,14 +30,17 @@ .col-xl-2.col %section.plantings + = cute_icon =render 'plantings' %p.text-right= link_to "#{t('home.plantings.view_all')} »", plantings_path, class: 'btn btn-block' .col-xl-2.col %section.harvests + = cute_icon = render 'harvests' %p.text-right= link_to "#{t('home.harvests.view_all')} »", harvests_path, class: 'btn btn-block' .col-12.col-md-6 %section.seeds + = cute_icon = render 'seeds' %p.text-right= link_to "#{t('home.seeds.view_all')} »", seeds_path, class: 'btn btn-block' .col-12.col-md-6 diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index 9376d9a02..3783b7059 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -1,20 +1,58 @@ %nav.navbar.navbar-expand-lg.navbar-dark.default-color.bg-dark - %a.navbar-brand.d-xs-none{ href: root_path } - = image_tag("growstuff-brand.png", size: "200x50", alt: ENV['GROWSTUFF_SITE_NAME']) - %a.navbar-brand.d-none.d-xs{ href: root_path } - = image_tag("growstuff-apple-touch-icon-precomposed.png", - size: "40x40", alt: ENV['GROWSTUFF_SITE_NAME']) - %button.navbar-toggler{"aria-controls" => "navbarSupportedContent", "aria-expanded" => "false", "aria-label" => "Toggle navigation", "data-target" => "#navbarSupportedContent", "data-toggle" => "collapse", type: "button"} - %span.navbar-toggler-icon + .row + .col-2.col-lg-4 + .d-none.d-lg-inline + %a.navbar-brand{ href: root_path } + = image_tag("growstuff-brand.png", size: "200x50", alt: ENV['GROWSTUFF_SITE_NAME']) + .d-inline.d-lg-none + %a.navbar-brand{ href: root_path } + = image_tag("growstuff-apple-touch-icon-precomposed.png", size: "40x40", + alt: ENV['GROWSTUFF_SITE_NAME']) + .col-8.col-lg-7 + = render 'crops/search_bar' + .col-2.col-lg-1 + %button.navbar-toggler{"aria-controls" => "navbarSupportedContent", "aria-expanded" => "false", "aria-label" => "Toggle navigation", "data-target" => "#navbarSupportedContent", "data-toggle" => "collapse", type: "button"} + %i.fas.fa-ellipsis-v.navbar-toggler-icon + #navbarSupportedContent.collapse.navbar-collapse %ul.navbar-nav.mr-auto + - if signed_in? + = link_to timeline_index_path, method: :get, class: 'nav-link text-white' do + = image_tag 'icons/notification.svg', class: 'img img-icon' + = link_to member_gardens_path(member_slug: current_member.slug), class: 'nav-link text-white' do + = image_icon 'gardens' + %li.nav-item.dropdown + %a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", href: "#", role: "button"} + = image_tag "icons/gardener.svg", class: 'img img-icon' + = t('.record') + .dropdown-menu + = link_to new_planting_path, class: 'dropdown-item' do + = image_icon('planting-add') + = t('buttons.new_planting') + = link_to new_harvest_path, class: 'dropdown-item' do + = image_icon('harvest-add') + = t('buttons.new_harvest') + = link_to new_seed_path, class: 'dropdown-item' do + = image_icon('seed-add') + = t('buttons.new_seeds') + = link_to new_post_path, class: 'dropdown-item' do + = post_icon + = t('buttons.new_post') + %li.nav-item.dropdown - %a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :href => "#", :role => "button"}= t('.crops') + %a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", href: "#", role: "button"}= t('.crops') .dropdown-menu - = link_to t('.browse_crops'), crops_path, class: 'dropdown-item' - = link_to t('.seeds'), seeds_path, class: 'dropdown-item' - = link_to t('.plantings'), plantings_path, class: 'dropdown-item' - = link_to t('.harvests'), harvests_path, class: 'dropdown-item' + = link_to crops_path, class: 'dropdown-item' do + = t('.browse_crops') + = link_to seeds_path, class: 'dropdown-item' do + = seed_icon + = t('.seeds') + = link_to plantings_path, class: 'dropdown-item' do + = planting_icon + = t('.plantings') + = link_to harvests_path, class: 'dropdown-item' do + = harvest_icon + = t('.harvests') %li.nav-item.dropdown %a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", href: "#", role: "button"}= t('.community') @@ -24,7 +62,6 @@ = link_to t('.posts'), posts_path, class: 'dropdown-item' = link_to t('.forums'), forums_path, class: 'dropdown-item' - - if member_signed_in? %li.nav-item.dropdown %a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", href: "#", role: "button"} @@ -70,4 +107,3 @@ - else %li.nav-item= link_to t('.sign_in'), new_member_session_path, id: 'navbar-signin', class: 'btn nav-link' %li.nav-item= link_to t('.sign_up'), new_member_registration_path, id: 'navbar-signup', class: 'btn nav-link' - = render 'crops/search_bar' diff --git a/app/views/layouts/_nav.haml b/app/views/layouts/_nav.haml index 07477f19a..7122a0e20 100644 --- a/app/views/layouts/_nav.haml +++ b/app/views/layouts/_nav.haml @@ -1,17 +1,15 @@ -%ul.nav - - if current_member.present? - %li.list-group-item.btn - = link_to url_for([current_member, model]) do +- if current_member.present? + %ul.nav.crop-actions + %li.nav-item.dropdown.btn.btn-sm + = link_to url_for([current_member, model]), class: 'nav-link' do My #{model.model_name.human.pluralize} + %li.nav-item.dropdown.btn.btn-sm + = link_to model, class: 'nav-link' do + Everyone's #{model.model_name.human.pluralize} + - if can?(:create, model) + %li.nav-item.dropdown.btn.btn-sm + = link_to url_for([model, action: :new]), class: 'nav-link' do + Add a #{model.model_name.human} - %li.list-group-item.btn - = link_to model do - Everyone's #{model.model_name.human.pluralize} - - - if can?(:create, model) - %li.list-group-item.btn - = link_to url_for([model, action: :new]) do - Add a #{model.model_name.human} - -- unless current_member - = render 'shared/signin_signup', to: "add a new #{model.to_s.downcase}" +- else + = render 'shared/signin_signup', to: "record your #{model.to_s.pluralize.downcase}" diff --git a/app/views/layouts/_pagination.html.haml b/app/views/layouts/_pagination.html.haml deleted file mode 100644 index a57470a4b..000000000 --- a/app/views/layouts/_pagination.html.haml +++ /dev/null @@ -1 +0,0 @@ -= will_paginate collection \ No newline at end of file diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index a378fc735..72bb495c5 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -9,17 +9,14 @@ %a{ name: 'skipnav' } #maincontainer.container-fluid .row - .col-12 - .layout-actions= render 'shared/global_actions' + .col-md-8.col-12 - if content_for?(:breadcrumbs) - .float-left - %nav{"aria-label" => "breadcrumb"} - %ol.breadcrumb - %li.breadcrumb-item= link_to 'Home', root_path - = yield(:breadcrumbs) - - - if content_for?(:buttonbar) - = yield(:buttonbar) + %nav + %ol.breadcrumb{"aria-label" => "breadcrumb"} + %li.breadcrumb-item= link_to 'Home', root_path + = yield(:breadcrumbs) + - if content_for?(:buttonbar) + = yield(:buttonbar) - if content_for?(:subtitle) %small= yield(:subtitle) diff --git a/app/views/layouts/modal.html.haml b/app/views/layouts/modal.html.haml new file mode 100644 index 000000000..8468a6b4c --- /dev/null +++ b/app/views/layouts/modal.html.haml @@ -0,0 +1,11 @@ +#mainModal.modal{"aria-hidden" => "true", "aria-labelledby" => "mainModalLabel", role: "dialog", tabindex: "-1"} + .modal-dialog + .modal-content + .modal-header + %button.close{"data-dismiss" => "modal", type: "button"} + %span{"aria-hidden" => "true"} × + %span.sr-only Close + %h4#mainModalLabel.modal-title + = yield :title if content_for? :title + \  + = yield diff --git a/app/views/members/_tiny.haml b/app/views/members/_tiny.haml index 4693bf373..95b51c2b0 100644 --- a/app/views/members/_tiny.haml +++ b/app/views/members/_tiny.haml @@ -1,4 +1,4 @@ -%span.member-chip +%span.chip.member-chip - if member.discarded? = icon 'fas', 'user-times' = member diff --git a/app/views/photos/_tiny.html.haml b/app/views/photos/_tiny.html.haml new file mode 100644 index 000000000..3e95fb558 --- /dev/null +++ b/app/views/photos/_tiny.html.haml @@ -0,0 +1,3 @@ +- if photo.present? + .photo + = image_tag(photo.thumbnail_url, alt: photo.title, class: 'img img-tiny') diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index 67f2da1a6..c286d8afc 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -13,11 +13,19 @@ .row{id: "photo-#{@photo.id}"} .col-md-9 - %h1.text-center.ellipsis - = photo_icon - = @photo.title - %p.text-center - = image_tag(@photo.fullsize_url, alt: @photo.title, class: 'rounded img-responsive shadow-sm') + %section.photo + %h2.text-center.ellipsis + = photo_icon + = @photo.title + + %p.text-center + = image_tag(@photo.fullsize_url, alt: @photo.title, class: 'rounded img-responsive shadow-sm') + + + - if @crops.size.positive? + .index-cards + - @crops.each do |crop| + = render 'crops/thumbnail', crop: crop .col-md-3 %p = render 'photos/actions', photo: @photo @@ -26,14 +34,11 @@ = icon 'fab', 'flickr' View on #{@photo.source.titleize} %span.btn= render 'photos/likes', photo: @photo - - - if @crops.size.positive? - - @crops.each do |crop| - = render 'crops/tiny', crop: crop - %p - = render 'members/tiny', member: @photo.owner - if @photo.date_taken.present? - Taken on #{I18n.l @photo.date_taken.to_date} + %h3 Taken on #{I18n.l @photo.date_taken.to_date} + + = render @photo.owner + %p %strong License: - if @photo.license_url diff --git a/app/views/plant_parts/index.html.haml b/app/views/plant_parts/index.html.haml index 34846e9c3..22c4784da 100644 --- a/app/views/plant_parts/index.html.haml +++ b/app/views/plant_parts/index.html.haml @@ -1,21 +1,25 @@ - content_for :title, "Plant parts" +%h1 Plant Parts + - if can? :create, PlantPart - = link_to 'New Plant part', new_plant_part_path + = link_to 'New Plant part', new_plant_part_path, class: 'btn btn-info' -- @plant_parts.each do |plant_part| - %h2= plant_part - %p - - if plant_part.crops.empty? - No crops are harvested for this plant part (yet). - - else - - plant_part.crops.limit(100).each do |crop| - = link_to(crop, crop_path(crop)) - %p - = link_to "More detail", plant_part - - %p - - if can? :edit, plant_part - = link_to 'Edit', edit_plant_part_path(plant_part), class: 'btn btn-default btn-xs' - - if can? :destroy, plant_part - = link_to 'Delete', plant_part, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' +.index-cards + - @plant_parts.each do |plant_part| + .card.plant-part + .card-header + %h2= link_to plant_part, plant_part + .card-body + %p + - if plant_part.crops.empty? + No crops are harvested for this plant part (yet). + - else + - plant_part.crops.limit(20).each do |crop| + = render 'crops/tiny', crop: crop + .card-footer + %p + - if can? :edit, plant_part + = link_to 'Edit', edit_plant_part_path(plant_part), class: 'btn btn-default btn-xs' + - if can? :destroy, plant_part + = link_to 'Delete', plant_part, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' diff --git a/app/views/plantings/_badges.html.haml b/app/views/plantings/_badges.html.haml index fd38ccb57..9d24a054e 100644 --- a/app/views/plantings/_badges.html.haml +++ b/app/views/plantings/_badges.html.haml @@ -7,18 +7,12 @@ = planting_finish_button(planting) - elsif planting.late? %span.badge.badge-info.badge-late= t('.late_finishing') - - else - %span.badge.badge-info{'data-toggle': "tooltip", 'data-placement': "top", title: 'Predicted days until planting is finished'} - = finished_icon - = t('label.days_until_finished', number: days_from_now_to_finished(planting)) // Harvest times - unless planting.super_late? - if planting.harvest_time? %span.badge.badge-info.badge-harvest{'data-toggle': "tooltip", 'data-placement': "top", title: 'Planting is ready for harvesting now'} - = harvest_icon = t('label.harvesting_now') - elsif planting.before_harvest_time? - %span.badge.badge-info{'data-toggle': "tooltip", 'data-placement': "top", title: 'Predicted days until harvest'} - = harvest_icon - = t('label.days_until_harvest', number: days_from_now_to_first_harvest(planting)) + %span.badge.badge-info{'data-toggle': "tooltip", 'data-placement': "top", title: 'Predicted weeks until harvest'} + = t('label.weeks_until_harvest', number: weeks_from_now_to_first_harvest(planting)) diff --git a/app/views/plantings/_card.html.haml b/app/views/plantings/_card.html.haml index 479815afa..2f9ffc6d9 100644 --- a/app/views/plantings/_card.html.haml +++ b/app/views/plantings/_card.html.haml @@ -1,4 +1,4 @@ -.card.planting-card.planting +.card.planting{class: planting.active? ? '' : 'card-finished'} = link_to planting do = image_tag planting_image_path(planting), class: 'img-card', alt: planting - if can? :edit, planting @@ -17,10 +17,8 @@ - if can? :destroy, planting .dropdown-divider = delete_button(planting, classes: 'dropdown-item text-danger') - - .card-body.text-center - %h4.card-title= link_to planting.crop, planting - .text-center= render 'plantings/badges', planting: planting - = render 'plantings/progress', planting: planting - -# .card-footer - -# .float-right=render 'members/tiny', member: planting.owner \ No newline at end of file + = link_to planting do + .card-body.text-center + %h4= planting.crop + .text-center= render 'plantings/badges', planting: planting + = render 'plantings/progress', planting: planting diff --git a/app/views/plantings/_descendants.html.haml b/app/views/plantings/_descendants.html.haml index 64f93a2c8..2dd31b8d0 100644 --- a/app/views/plantings/_descendants.html.haml +++ b/app/views/plantings/_descendants.html.haml @@ -1,9 +1,17 @@ %h2 Seeds saved + +%a.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", role: "button"} + = seed_icon + = t('buttons.save_seeds') +.dropdown-menu.dropdown-secondary + - Seed::TRADABLE_TO_VALUES.each do |trade| + = link_to seeds_path(return: 'planting', seed: {crop_id: planting.crop.id, parent_planting_id: planting.id, tradable_to: trade}), method: :post, class: 'dropdown-item' do + Will trade: + = trade + - if planting.child_seeds.size.positive? .index-cards - planting.child_seeds.each do |seed| = render 'seeds/card', seed: seed - else %p No seeds saved - -= planting_save_seeds_button(planting) diff --git a/app/views/plantings/_facts.haml b/app/views/plantings/_facts.haml index a6afb8122..4afd14ca7 100644 --- a/app/views/plantings/_facts.haml +++ b/app/views/plantings/_facts.haml @@ -7,43 +7,63 @@ = seed_icon %span=planting.parent_seed - - if planting.finished? - .card.fact-card + - if planting.planted_at.present? + .card.fact-card{class: planting.planted_at.present? ? '' : 'text-muted'} %h3 Planted - %strong=planting_icon - - if planting.quantity.present? - %span.plantingfact--quantity= planting.quantity + %strong.plantingfact--plantedmonth + = I18n.t('date.abbr_month_names')[planting.planted_at.month] + %span=planting.planted_at.year - - if planting.planted_at.present? && !planting.finished? - .card.fact-card - %h3 Planted - %strong.plantingfact--dayssinceplanted #{planting.days_since_planted} - %span days ago - - if planting.quantity.to_i.positive? - .card.fact-card - %h3 Quantity - %strong.plantingfact--quantity= planting.quantity - %span - - if planting.planted_from.present? - #{pluralize((planting.quantity.to_i), planting.planted_from)} + .card.fact-card{class: planting.planted_at.present? ? '' : 'text-muted'} + %h3 + Planted + = editable :date, planting, :planted_at, display_field: '.planted_at' + %strong.plantingfact--weekssinceplanted.planted_at + - if planting.planted_at.present? + #{planting.weeks_since_planted} + - else + unknown + %span.planted_at weeks ago + - if planting.planted_at.present? + %span.plantingfact--planttedat.planted_at + = I18n.l planting.planted_at + + + + .card.fact-card{class: planting.quantity.present? ? '' : 'text-muted'} + %h3 + Quantity + %small= editable :text_field, planting, :quantity, display_field: '.plantingfact--quantity' + %strong.plantingfact--quantity + - if planting.quantity.to_i.positive? + = planting.quantity + -else + unknown + %span + - if planting.quantity.to_i.positive? && planting.planted_from.present? + = planting.planted_from.pluralize(planting.quantity.to_i) - unless planting.finished? .card.fact-card.grid-sizer %h3 Growing %strong= seedling_icon - - if planting.planted_at.present? - %span.plantingfact--planttedat= I18n.l planting.planted_at.to_date + %span + Planting is still growing today + .card.fact-card{class: planting.planted_from.present? ? '' : 'text-muted'} + %h3 + Grown from + = editable :select, planting, :planted_from, collection: Planting::PLANTED_FROM_VALUES, display_field: '.plantingfact--plantedfrom' + %strong.plantingfact--plantedfrom + = planting.planted_from.present? ? planting.planted_from : 'unknown' - - if planting.planted_from.present? - .card.fact-card - %h3 Grown from - %span.plantingfact--plantedfrom=planting.planted_from - - .card.fact-card - %h3 Grown in + .card.fact-card{class: planting.sunniness.present? ? '' : 'text-muted'} + %h3 + Grown in + = editable :select, planting, :sunniness, collection: Planting::SUNNINESS_VALUES, display_field: '.plantingfact--sunniness' %strong= sunniness_icon(planting.sunniness) - %span.plantingfact--sunniness= planting.sunniness.blank? ? "not specified" : planting.sunniness + %span.plantingfact--sunniness + = planting.sunniness.blank? ? "not specified" : planting.sunniness .card.fact-card %h3.plantingfact--harveststitle @@ -51,8 +71,9 @@ %strong = link_to planting_harvests_path(planting) do = harvest_icon - %span.plantingfact--harvestprediction - = planting.first_harvest_date&.to_formatted_s(:rfc822) || planting&.first_harvest_predicted_at&.to_formatted_s(:rfc822) || 'unknown' + - if planting.first_harvest_date.present? || planting.first_harvest_predicted_at.present? + %span.plantingfact--harvestprediction + = I18n.l(planting.first_harvest_date || planting&.first_harvest_predicted_at || 'unknown') - if planting.crop.perennial .card.fact-card @@ -61,16 +82,20 @@ - else - if !planting.finished? && planting.finish_is_predicatable? .card.fact-card - - days = days_from_now_to_finished(planting) - - if days.positive? - %h3.plantingfact--finishtitle Prediction - %strong.plantingfact--finisheddays #{days} - %span days until finished + %h3.plantingfact--finishtitle Predicted Finish + %strong.plantingfact--finishedmonth + = I18n.t('date.abbr_month_names')[planting.finish_predicted_at.month] + %span=planting.finish_predicted_at.year + + .card.fact-card + %h3.plantingfact--finishtitle Predicted Finish + - if days_from_now_to_finished(planting).positive? + %strong.plantingfact--finisheddays= weeks_from_not_to_finished(planting) + %span weeks - else - %h3.plantingfact--finishtitle Finished - %strong.plantingfact--finisheddays #{days * -1} - %span days ago - %span= planting.finish_predicted_at&.to_formatted_s(:rfc822) + %strong.plantingfact--finisheddays #{weeks_from_not_to_finished(planting) * -1} + %span weeks ago + %span= I18n.l planting.finish_predicted_at - if planting.child_seeds.size.positive? .card.fact-card @@ -84,5 +109,7 @@ .card.fact-card %h3 Finished %strong=finished_icon - %span.plantingfact--finish=planting.finished_at&.to_formatted_s(:rfc822) - + - if planting.finished_at.present? + %span.plantingfact--finish + = I18n.t('date.abbr_month_names')[planting.finished_at.month] + = planting.finished_at.year diff --git a/app/views/plantings/_harvests.html.haml b/app/views/plantings/_harvests.html.haml index ec3933ef1..aa3a0fd40 100644 --- a/app/views/plantings/_harvests.html.haml +++ b/app/views/plantings/_harvests.html.haml @@ -1,4 +1,15 @@ %h2 Harvests + +- if can? :edit, @planting + %a.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", :href => "#", :role => "button"} + = harvest_icon + Record harvest + + .dropdown-menu.dropdown-secondary + - PlantPart.all.each do |plant_part| + = link_to harvests_path(return: 'planting', harvest: {crop_id: @planting.crop_id, planting_id: @planting.id, plant_part_id: plant_part.id}), method: :post, class: 'dropdown-item' do + = plant_part.name + - if planting.harvests.empty? %p No harvests recorded - if !planting.finished? && can?(:edit, planting) && can?(:create, Harvest) @@ -6,6 +17,4 @@ - else .index-cards - planting.harvests.order(created_at: :desc).includes(:crop).each do |harvest| - = render 'harvests/card', harvest: harvest - -= planting_harvest_button(planting) + = render 'harvests/thumbnail', harvest: harvest diff --git a/app/views/plantings/_photos.haml b/app/views/plantings/_photos.haml index f27f2864d..800b42828 100644 --- a/app/views/plantings/_photos.haml +++ b/app/views/plantings/_photos.haml @@ -4,7 +4,9 @@ - if can?(:edit, planting) && can?(:create, Photo) %p.text-right= add_photo_button(planting) %p.text-right - = link_to 'more photos', planting_photos_path(planting), class: 'btn' + = link_to planting_photos_path(planting), class: 'btn' do + = photo_icon + more photos - else %p No photos. - if can?(:edit, planting) && can?(:create, Photo) diff --git a/app/views/plantings/_progress.html.haml b/app/views/plantings/_progress.html.haml index a26fa646a..a61233f3e 100644 --- a/app/views/plantings/_progress.html.haml +++ b/app/views/plantings/_progress.html.haml @@ -1,8 +1,11 @@ -- if planting.annual? && planting.percentage_grown.present? +- if planting.active? && planting.annual? && planting.percentage_grown.present? .progress - .progress-bar.bg-success{"aria-valuemax" => "100", "aria-valuemin" => "0", "aria-valuenow" => planting.percentage_grown, :role => "progressbar", :style => "width: #{planting.percentage_grown}%; height: 25px"} + .progress-bar.bg-success{"aria-valuemax" => "100", "aria-valuemin" => "0", "aria-valuenow" => planting.percentage_grown, role: "progressbar", style: "width: #{planting.percentage_grown}%"} .float-left #{sprintf '%.0f', planting.percentage_grown}% - unless planting.finish_predicted_at.blank? - .float-right= planting.finish_predicted_at.strftime(Date::DATE_FORMATS[:ymd]) + .float-right + -# = planting.finish_predicted_at.strftime(Date::DATE_FORMATS[:ymd]) + = I18n.t('date.abbr_month_names')[planting.finish_predicted_at.month] + = planting.finish_predicted_at.year diff --git a/app/views/plantings/_progress_list.haml b/app/views/plantings/_progress_list.haml new file mode 100644 index 000000000..79e9f0246 --- /dev/null +++ b/app/views/plantings/_progress_list.haml @@ -0,0 +1,15 @@ +- plantings.includes(:crop).annual.order("crops.name").each_with_index do |planting, i| + - if i.positive? + %hr/ + .row.progress-row + .col-6.col-md-4.progress-row--crop + = render 'plantings/tiny', planting: planting + = render 'plantings/badges', planting: planting + .col-6.col-md-6.progress-row--bar + - if planting.planted_at.blank? + %small set "planted" date to allow predictions + - elsif planting.percentage_grown.blank? + %small not enough data on #{planting.crop} to predict + - else + = render 'plantings/progress', planting: planting + .col-12.col-md-2= render 'plantings/quick_actions', planting: planting diff --git a/app/views/plantings/_quick_actions.haml b/app/views/plantings/_quick_actions.haml index a2e4c6fac..61d173ef2 100644 --- a/app/views/plantings/_quick_actions.haml +++ b/app/views/plantings/_quick_actions.haml @@ -1,16 +1,14 @@ - if can?(:edit, planting) - .planting-quick-actions.text-right - %a.btn#actionsMenu.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", href: "#"} - -# =icon('fas', 'ellipsis-v') - %ul.dropdown-menu.dropdown-menu-left{"aria-labelledby" => "actionsMenu"} - %li.btn-xs - = link_to t('view'), planting, class: 'btn' - %li.btn-xs= planting_edit_button(planting) - %li.btn-xs= add_photo_button(planting) + %a#planting-actions-menu.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", href: "#"} + /=icon('fas', 'ellipsis-v') + %ul.dropdown-menu.dropdown-menu-left{"aria-labelledby" => "planting-actions-menu"} + %li= link_to t('view'), planting, class: 'dropdown-item' + %li= planting_edit_button(planting, classes: 'dropdown-item') + %li= add_photo_button(planting, classes: 'dropdown-item') - - if planting.active? - %li.btn-xs= planting_finish_button(planting) - %li.btn-xs= planting_harvest_button(planting) - %li.btn-xs= planting_save_seeds_button(planting) + - if planting.active? + %li= planting_finish_button(planting, classes: 'dropdown-item') + %li= planting_harvest_button(planting, classes: 'dropdown-item') + %li= planting_save_seeds_button(planting, classes: 'dropdown-item') diff --git a/app/views/plantings/_tiny.html.haml b/app/views/plantings/_tiny.html.haml new file mode 100644 index 000000000..ccffd765a --- /dev/null +++ b/app/views/plantings/_tiny.html.haml @@ -0,0 +1,4 @@ += link_to planting do + .chip.crop-chip + = crop_icon(planting.crop) + = planting.crop.name diff --git a/app/views/plantings/index.html.haml b/app/views/plantings/index.html.haml index 407a97b41..6e5f53ffe 100644 --- a/app/views/plantings/index.html.haml +++ b/app/views/plantings/index.html.haml @@ -11,32 +11,32 @@ = planting_icon = title('plantings', @owner, @crop, @planting) -= render 'layouts/nav', model: Planting - - -%section.border-top - .btn-group - = link_to plantings_active_tickbox_path(@owner, @show_all), class: 'btn' do - = check_box_tag 'active', 'all', @show_all - include in-active - - - if @owner - = link_to t('.view_owners_profile', owner: @owner), member_path(@owner), class: 'btn' +.row + .col + %ul.nav + %li.list-group-item + = link_to show_inactive_tickbox_path('plantings', owner: @owner, show_all: @show_all) do + = check_box_tag 'active', 'all', @show_all + include finished + - if @owner + %li.list-group-item.btn + = link_to t('.view_owners_profile', owner: @owner), member_path(@owner) + .col= render 'layouts/nav', model: Planting .row .col-12= page_entries_info @plantings - .col-12= render 'layouts/pagination', collection: @plantings + .col-12= will_paginate @plantings .index-cards - @plantings.each do |planting| = render planting, full: true -.row - .col-12= page_entries_info @plantings - .col-12= render 'layouts/pagination', collection: @plantings += will_paginate @plantings + +%hr/ %section.open-data - %h5= t('label.data') + %h3= t('label.data') %ul.nav#open-data - ['csv', 'json', 'rss'].each do |format| %li.list-group-item diff --git a/app/views/plantings/show.html.haml b/app/views/plantings/show.html.haml index f173b2ba4..a736dcb67 100644 --- a/app/views/plantings/show.html.haml +++ b/app/views/plantings/show.html.haml @@ -20,13 +20,14 @@ %h1.plantingtitle %span.plantingtitle--icon= planting_icon = @planting.to_s.titleize - + .col-md-4.col-xs-12 = render 'plantings/actions', planting: @planting + .col-md-8.col-xs-12 %section= render 'facts', planting: @planting - - if @planting.description.present? %hr/ + = cute_icon .card .card-header %h2 Notes @@ -36,7 +37,8 @@ %section= render 'plantings/photos', photos: @photos, planting: @planting .col-md-4.col-xs-12 - if @planting.percentage_grown - .card + %section.progress-bar + %h2 Progress .progress .progress-bar{"aria-valuemax" => "100", "aria-valuemin" => "0", "aria-valuenow" => @planting.percentage_grown, role: "progressbar", style: "width: #{@planting.percentage_grown}%"} %strong.plantingfact--percentagegrown @@ -46,6 +48,10 @@ = render @planting.crop .row .col-md-6 - %section= render 'plantings/harvests', planting: @planting + %section.harvests + %a{name: 'harvests'} + = render 'plantings/harvests', planting: @planting .col-md-6 - %section= render 'plantings/descendants', planting: @planting + %section.descendants + %a{name: 'seeds'} + = render 'plantings/descendants', planting: @planting diff --git a/app/views/posts/_single.html.haml b/app/views/posts/_single.html.haml index 0057e7367..10a372b6d 100644 --- a/app/views/posts/_single.html.haml +++ b/app/views/posts/_single.html.haml @@ -17,32 +17,3 @@ :growstuff_markdown #{ strip_tags @post.body } - --# .card --# .post{ id: "post-#{post.id}" } --# .row --# .col-md-1 --# = render partial: "members/avatar", locals: { member: post.author } --# .col-md-11 --# - if defined?(subject) --# %h3= link_to strip_tags(post.subject), post - --# .post-meta --# %p --# Posted by --# - if post.author --# = link_to post.author.login_name, member_path(post.author) --# - else --# Member Deleted --# - if post.forum --# in --# = link_to post.forum, post.forum --# on --# = post.created_at --# - if post.updated_at > post.created_at --# and edited at --# = post.updated_at - --# .post-body --# :growstuff_markdown --# #{ strip_tags post.body } diff --git a/app/views/posts/show.html.haml b/app/views/posts/show.html.haml index f7d09a620..efa29e670 100644 --- a/app/views/posts/show.html.haml +++ b/app/views/posts/show.html.haml @@ -56,11 +56,11 @@ .col-md-4.col-12 = render @post.author - - unless @post.crops.empty? + - unless @post.crops.approved.empty? %section.crops %h2 Crops mentioned in this post .index-cards - - @post.crops.each do |c| + - @post.crops.approved.each do |c| = render 'crops/thumbnail', crop: c diff --git a/app/views/scientific_names/_form.html.haml b/app/views/scientific_names/_form.html.haml index 95178f068..95f768aa7 100644 --- a/app/views/scientific_names/_form.html.haml +++ b/app/views/scientific_names/_form.html.haml @@ -17,7 +17,7 @@ .form-group = f.label :crop_id, class: 'control-label col-md-2' .col-md-8 - = collection_select(:scientific_name, :crop_id, Crop.all, :id, + = collection_select(:scientific_name, :crop_id, Crop.all.order(:name), :id, :name, { selected: @scientific_name.crop_id || @crop.id }, class: 'form-control') .form-group diff --git a/app/views/seeds/_card.html.haml b/app/views/seeds/_card.html.haml index a6a975ef2..45164e45b 100644 --- a/app/views/seeds/_card.html.haml +++ b/app/views/seeds/_card.html.haml @@ -1,12 +1,12 @@ -.card.seed-card +.card.seed-card{class: seed.active? ? '' : 'card-finished'} = link_to seed do = image_tag(seed_image_path(seed), alt: seed, class: 'img-card') + .text + = render 'members/tiny', member: seed.owner .card-body .card-title = crop_icon(seed.crop) = link_to seed.crop, seed - .card-footer - = render 'members/tiny', member: seed.owner - if seed.tradable? .text-muted = icon 'fas', 'map' diff --git a/app/views/seeds/_facts.html.haml b/app/views/seeds/_facts.html.haml index 51e19212c..ea155b123 100644 --- a/app/views/seeds/_facts.html.haml +++ b/app/views/seeds/_facts.html.haml @@ -1,24 +1,36 @@ .index-cards.facts.seedfacts - .card - %h3 Quantity + .card{class: seed.quantity.present? ? '' : 'text-muted'} + %h3 + Quantity + = editable :text_field, seed, :quantity, display_field: '.seedfacts--quantity' %strong.seedfacts--quantity= seed.quantity.blank? ? "not specified" : seed.quantity - %span seeds + %span + seeds - - if seed.plant_before.present? - .card.seedfacts--card - %h3 Plant before - %strong.seedfacts--plantbefore= I18n.l(seed.plant_before) + .card.seedfacts--card{class: seed.plant_before.present? ? '' : 'text-muted'} + %h3 + Plant before + = editable :date, seed, :plant_before, display_field: '.seedfacts--plantbefore' + %strong.seedfacts--plantbefore + - if seed.plant_before.present? + = I18n.l(seed.plant_before) + - else + Unknown -if seed.finished_at.present? .card %h3 Finished at - %strong.seedfacts--finishedat= I18n.l(seed.finished_at) - .card + + .card{class: seed.days_until_maturity_max.present? ? '' : 'text-muted'} %h3 Days until maturity - %strong.seedfacts--maturity= render partial: 'days_until_maturity', locals: { seed: seed } + %strong.seedfacts--maturity + = render partial: 'days_until_maturity', locals: { seed: seed } + %span days .card - %h3 Will trade + %h3 + Will trade + = editable :select, seed, :tradable_to, collection: Seed::TRADABLE_TO_VALUES, display_field: '.seedfacts--tradableto' %strong.seedfacts--tradableto= seed.tradable_to %span - if seed.owner.location.blank? diff --git a/app/views/seeds/_seed.haml b/app/views/seeds/_seed.haml index af5f6203f..b6cd078e2 100644 --- a/app/views/seeds/_seed.haml +++ b/app/views/seeds/_seed.haml @@ -3,4 +3,4 @@ = render 'seeds/card', seed: seed - else - cache seed do - = render 'seeds/thumbnail', seed: seed \ No newline at end of file + = render 'seeds/thumbnail', seed: seed diff --git a/app/views/seeds/index.html.haml b/app/views/seeds/index.html.haml index 103fe7292..6c74b13d3 100644 --- a/app/views/seeds/index.html.haml +++ b/app/views/seeds/index.html.haml @@ -1,17 +1,3 @@ -- content_for :title, title('seeds', @owner, @crop, @planting) -%h1 - = seed_icon - = title('seeds', @owner, @crop, @planting) - -- if @owner - = link_to "View #{@owner}'s profile >>", member_path(@owner) - -%p - #{ENV['GROWSTUFF_SITE_NAME']} helps you track your seed - stash or trade seeds with other members. - -= render 'layouts/nav', model: Seed - - content_for :breadcrumbs do - if @owner %li.breadcrumb-item= link_to 'Seeds', seeds_path @@ -19,16 +5,32 @@ - else %li.breadcrumb-item.active= link_to 'Seeds', seeds_path +- content_for :title, title('seeds', @owner, @crop, @planting) +%h1 + = seed_icon + = title('seeds', @owner, @crop, @planting) + +.row + .col + %ul.nav + %li.list-group-item + = link_to show_inactive_tickbox_path('seeds', owner: @owner, show_all: @show_all) do + = check_box_tag 'active', 'all', @show_all + include finished + - if @owner + %li.list-group-item.btn + = link_to t('.view_owners_profile', owner: @owner), member_path(@owner) + .col= render 'layouts/nav', model: Seed - unless @seeds.empty? - .pagination - = page_entries_info @seeds - = will_paginate @seeds - .index-cards= render @seeds, full: true + = page_entries_info @seeds + = will_paginate @seeds - .pagination - = page_entries_info @seeds - = will_paginate @seeds + .index-cards + - @seeds.each do |seed| + = render 'seeds/card', seed: seed + + = will_paginate @seeds %section.open-data %h5= t('label.data') diff --git a/app/views/seeds/show.html.haml b/app/views/seeds/show.html.haml index 7ada4e8d9..d2f2a717f 100644 --- a/app/views/seeds/show.html.haml +++ b/app/views/seeds/show.html.haml @@ -15,61 +15,66 @@ %li.breadcrumb-item= link_to @seed.owner, member_seeds_path(@seed.owner) %li.breadcrumb-item.active= link_to @seed, @seed -.row.seeds - .col-md-8 - %h1 - %span.seedtitle--icon= crop_icon(@seed.crop) - %strong - %span.seedtitle--owner #{@seed.owner}'s - %span.seedtitle--crop #{@seed.crop} - seeds - - if @seed.organic != 'unknown' - %small.seedtitle--organic= @seed.organic - - if @seed.gmo != 'unknown' - %small.seedtitle--gmo= @seed.gmo - - if @seed.heirloom != 'unknown' - %small.seedtitle--heirloom= @seed.heirloom - = I18n.l @seed.created_at.to_date +.seed + .row + .col-md-8.col-xs-12 + %h1 + %span.seedtitle--icon= crop_icon(@seed.crop) + %strong + %span.seedtitle--owner #{@seed.owner}'s + %span.seedtitle--crop #{@seed.crop} + seeds + - if @seed.organic != 'unknown' + %small.seedtitle--organic= @seed.organic + - if @seed.gmo != 'unknown' + %small.seedtitle--gmo= @seed.gmo + - if @seed.heirloom != 'unknown' + %small.seedtitle--heirloom= @seed.heirloom + = I18n.l @seed.created_at.to_date - = render 'seeds/actions', seed: @seed + .col-md-4.col-xs-12 + = render 'seeds/actions', seed: @seed - %section= render 'facts', seed: @seed - - if @seed.parent_planting - %dt Saved from planting: - %dd - = link_to @seed.parent_planting, planting_path(@seed.parent_planting) - - unless @seed.description.blank? - .card.seed--description - .card-header - %h2 Notes - .card-body - :growstuff_markdown - #{ @seed.description != "" ? strip_tags(@seed.description) : "No description given." } + .col-md-8.col-xs-12 + %section= render 'facts', seed: @seed + - if @seed.parent_planting + %dt Saved from planting: + %dd + = link_to @seed.parent_planting, planting_path(@seed.parent_planting) + - unless @seed.description.blank? + = cute_icon + .card.seed--description + .card-header + %h2 Notes + .card-body + :growstuff_markdown + #{strip_tags(@seed.description)} - - if current_member - - if @seed.tradable? && current_member != @seed.owner - %p= link_to "Request seeds", - new_message_path(recipient_id: @seed.owner.id, - subject: "Interested in your #{@seed.crop} seeds"), - class: 'btn btn-primary' - - else - = render 'shared/signin_signup', to: 'request seeds' + - if current_member + - if @seed.tradable? && current_member != @seed.owner + %p= link_to "Request seeds", + new_message_path(recipient_id: @seed.owner.id, + subject: "Interested in your #{@seed.crop} seeds"), + class: 'btn btn-primary' + - else + = render 'shared/signin_signup', to: 'request seeds' - %section= render 'seeds/descendants', seed: @seed - %section.seed-photos - - @photos.each do |photo| - = render 'photos/hero', photo: photo - %p - %small - Or - = link_to "purchase seeds via Ebay", - crop_ebay_seeds_url(@seed.crop), target: "_blank", rel: "noopener noreferrer", class: 'btn' - - if @seed.owner.location + %section.plantings + = render 'seeds/descendants', seed: @seed + %section.seed-photos + - @photos.each do |photo| + = render 'photos/hero', photo: photo %p %small - View other seeds, members to trade with and more near - = link_to @seed.owner.location, place_path(@seed.owner.location, anchor: "seeds") - .col-md-4 - = render 'seeds/owner' - = render @seed.crop + Or + = link_to "purchase seeds via Ebay", + crop_ebay_seeds_url(@seed.crop), target: "_blank", rel: "noopener noreferrer", class: 'btn' + - if @seed.owner.location + %p + %small + View other seeds, members to trade with and more near + = link_to @seed.owner.location, place_path(@seed.owner.location, anchor: "seeds") + .col-md-4.col-xs-12 + = render 'seeds/owner' + = render @seed.crop diff --git a/app/views/shared/_global_actions.html.haml b/app/views/shared/_global_actions.html.haml deleted file mode 100644 index a40849af9..000000000 --- a/app/views/shared/_global_actions.html.haml +++ /dev/null @@ -1,25 +0,0 @@ -- if signed_in? - .btn-group - = link_to member_gardens_path(member_slug: current_member.slug), - class: 'btn btn-default', 'data-toggle': "tooltip", 'data-placement': "bottom", title: t('buttons.my_gardens') do - = garden_icon - - = link_to timeline_index_path, - class: 'btn btn-default', 'data-toggle': "tooltip", 'data-placement': "bottom", title: t('buttons.timeline') do - = timeline_icon - - = link_to new_planting_path, - class: 'btn btn-default', 'data-toggle': "tooltip", 'data-placement': "bottom", title: t('buttons.new_planting') do - = planting_icon - - = link_to new_harvest_path, - class: 'btn btn-default', 'data-toggle': "tooltip", 'data-placement': "bottom", title: t('buttons.new_harvest') do - = harvest_icon - - = link_to new_seed_path, - class: 'btn btn-default', 'data-toggle': "tooltip", 'data-placement': "bottom", title: t('buttons.new_seeds') do - = seed_icon - - = link_to new_post_path, - class: 'btn btn-default', 'data-toggle': "tooltip", 'data-placement': "bottom", title: t('buttons.new_post') do - = post_icon diff --git a/app/views/shared/_signin_signup.html.haml b/app/views/shared/_signin_signup.html.haml index 5fae2b0bd..51c7a5ac2 100644 --- a/app/views/shared/_signin_signup.html.haml +++ b/app/views/shared/_signin_signup.html.haml @@ -1,7 +1,6 @@ -%p - = link_to 'Sign in', new_member_session_path, class: 'btn btn-success' - or - = link_to 'sign up', new_member_registration_path, class: 'btn btn-info' - to - = succeed "." do - = to += link_to 'Sign in', new_member_session_path, class: 'btn btn-success' +or += link_to 'sign up', new_member_registration_path, class: 'btn btn-info' +to += succeed "." do + = to diff --git a/app/views/shared/editable/_date.html.haml b/app/views/shared/editable/_date.html.haml new file mode 100644 index 000000000..3e9fccfbb --- /dev/null +++ b/app/views/shared/editable/_date.html.haml @@ -0,0 +1,11 @@ +- if can? :edit, model + %small.edit-link + %a.editable-date#description{"data-field" => "#date--#{model.id}-#{field.to_s}", + "data-display": display_field, href: "#"} + = edit_icon + .hide{id: "date--#{model.id}-#{field.to_s}"} + = bootstrap_form_for(model) do |f| + = f.text_field field, + value: model.send(field) ? model.send(field).to_s(:ymd) : '', + class: 'add-datepicker', label: 'When?' + = f.submit :save diff --git a/app/views/shared/editable/_form.html.haml b/app/views/shared/editable/_form.html.haml new file mode 100644 index 000000000..1c51efdae --- /dev/null +++ b/app/views/shared/editable/_form.html.haml @@ -0,0 +1,18 @@ +- if can? :edit, model + %small.edit-link + %a.editable{"data-form" => "#form--#{model.id}-#{field.to_s}", "data-display": display_field, href: "#", name: "#form--#{model.id}-#{field.to_s}"} + = edit_icon + + .hide{id: "form--#{model.id}-#{field.to_s}"} + = bootstrap_form_for(model) do |f| + - if field_type == :text_area + = f.text_area field + - elsif field_type == :text_field + = f.text_field field + - elsif field_type == :select + = f.select field, collection + - elsif field_type == :date + = f.text_field field, + value: model.send(field) ? model.send(field).to_s(:ymd) : '', + class: 'add-datepicker', label: 'When?' + = f.submit :save diff --git a/config/locales/en.yml b/config/locales/en.yml index e14b1a037..5285d5569 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -206,7 +206,9 @@ en: number_plantings_linktext: "%{count} times" label: days_until_harvest: "%{number} days" + weeks_until_harvest: "%{number} weeks until harvest" days_until_finished: "%{number} days" + weeks_until_finished: "%{number} weeks" harvesting_now: harvesting now data: 'The data on this page is available in the following formats:' layouts: @@ -226,6 +228,7 @@ en: gardens: Gardens harvest: Harvest harvests: Harvests + record: Record inbox: Inbox inbox_unread: Inbox (%{unread_count}) plantings: Plantings diff --git a/spec/controllers/charts/gardens_controller_spec.rb b/spec/controllers/charts/gardens_controller_spec.rb index 1eb959b29..d264388f6 100644 --- a/spec/controllers/charts/gardens_controller_spec.rb +++ b/spec/controllers/charts/gardens_controller_spec.rb @@ -9,7 +9,7 @@ describe Charts::GardensController do describe 'GET timeline' do before { get :timeline, params: { garden_id: garden.to_param } } - it { expect(response).to be_success } + it { expect(response).to be_successful } end end @@ -21,7 +21,7 @@ describe Charts::GardensController do describe 'GET timeline' do before { get :timeline, params: { garden_id: garden.to_param } } - it { expect(response).to be_success } + it { expect(response).to be_successful } end end end diff --git a/spec/features/crops/crop_detail_page_spec.rb b/spec/features/crops/crop_detail_page_spec.rb index 057226c4a..2602673b0 100644 --- a/spec/features/crops/crop_detail_page_spec.rb +++ b/spec/features/crops/crop_detail_page_spec.rb @@ -1,6 +1,9 @@ require 'rails_helper' describe "crop detail page", js: true do + before do + FactoryBot.create :plant_part, name: 'leaf' + end subject do # Update the medians after all the # data has been loaded @@ -26,13 +29,16 @@ describe "crop detail page", js: true do before { subject } it "has a link to plant the crop" do - expect(page).to have_link "Plant #{crop.name}", href: new_planting_path(crop_id: crop.id) + click_link 'Add to garden' + expect(page).to have_link "add new garden" end it "has a link to harvest the crop" do - expect(page).to have_link "Harvest #{crop.name}", href: new_harvest_path(crop_id: crop.id) + click_link 'Record harvest' + expect(page).to have_link "leaf" end it "has a link to add seeds" do - expect(page).to have_link "Add #{crop.name} seeds to stash", href: new_seed_path(crop_id: crop.id) + click_link 'Save seeds' + expect(page).to have_link "Will trade: nowhere" end end diff --git a/spec/features/gardens/index_spec.rb b/spec/features/gardens/index_spec.rb index 526bba7c9..ba3d137d2 100644 --- a/spec/features/gardens/index_spec.rb +++ b/spec/features/gardens/index_spec.rb @@ -103,8 +103,7 @@ describe "Gardens#index", :js do it { expect(page).to have_link href: planting_path(planting) } it { expect(page).to have_link href: garden_path(planting.garden) } - it { expect(page).to have_text '50 days' } - it { expect(page).to have_text '90 days' } + it { expect(page).to have_text '7 weeks' } it { expect(page).not_to have_text 'harvesting now' } end @@ -120,8 +119,7 @@ describe "Gardens#index", :js do it { expect(crop.median_lifespan).to eq 90 } it { expect(page).to have_text 'harvesting now' } - it { expect(page).to have_text '39 days' } - it { expect(page).not_to have_text 'Predicted days until harvest' } + it { expect(page).not_to have_text 'Predicted weeks until harvest' } end describe 'super late' do @@ -133,8 +131,8 @@ describe "Gardens#index", :js do it { expect(page).to have_text 'super late' } it { expect(page).not_to have_text 'harvesting now' } - it { expect(page).not_to have_text 'Predicted days until harvest' } - it { expect(page).not_to have_text 'Predicted days until planting is finished' } + it { expect(page).not_to have_text 'Predicted weeks until harvest' } + it { expect(page).not_to have_text 'Predicted weeks until planting is finished' } end end end diff --git a/spec/features/harvests/harvesting_a_crop_spec.rb b/spec/features/harvests/harvesting_a_crop_spec.rb index e7aeea3d6..a3261525a 100644 --- a/spec/features/harvests/harvesting_a_crop_spec.rb +++ b/spec/features/harvests/harvesting_a_crop_spec.rb @@ -47,14 +47,8 @@ describe "Harvesting a crop", :js, :elasticsearch do describe "Harvesting from crop page" do before do visit crop_path(maize) - within '.crop-actions' do - click_link "Harvest #{maize.name}" - end - within "form#new_harvest" do - choose plant_part.name - expect(page).to have_selector "input[value='maize']" - click_button "Save" - end + click_link 'Record harvest' + click_link plant_part.name end it { expect(page).to have_content "harvest was successfully created." } @@ -65,10 +59,8 @@ describe "Harvesting a crop", :js, :elasticsearch do let!(:planting) { create :planting, crop: maize, owner: member, garden: member.gardens.first } before do visit planting_path(planting) - click_link "Record Harvest" - - choose plant_part.name - click_button "Save" + click_link "Record harvest" + click_link plant_part.name end it { expect(page).to have_content "harvest was successfully created." } diff --git a/spec/features/plantings/planting_a_crop_spec.rb b/spec/features/plantings/planting_a_crop_spec.rb index 5a262ecbb..b6eb4fe76 100644 --- a/spec/features/plantings/planting_a_crop_spec.rb +++ b/spec/features/plantings/planting_a_crop_spec.rb @@ -2,8 +2,8 @@ require "rails_helper" require 'custom_matchers' describe "Planting a crop", :js, :elasticsearch do - let!(:maize) { FactoryBot.create :maize } - let(:garden) { FactoryBot.create :garden, owner: member } + let!(:maize) { FactoryBot.create :maize } + let(:garden) { FactoryBot.create :garden, owner: member, name: 'Orchard' } let!(:planting) do FactoryBot.create :planting, garden: garden, owner: member, planted_at: Date.parse("2013-03-10") end @@ -160,16 +160,8 @@ describe "Planting a crop", :js, :elasticsearch do it "Planting from crop page" do visit crop_path(maize) - within '.crop-actions' do - click_link "Plant maize" - end - within "form#new_planting" do - expect(page).to have_selector "input[value='maize']" - end - - choose(member.gardens.first.name) - click_button "Save" - + click_link "Add to garden" + click_link "Orchard" expect(page).to have_content "planting was successfully created" expect(page).to have_content "maize" end @@ -224,7 +216,7 @@ describe "Planting a crop", :js, :elasticsearch do end expect(page).to have_content "planting was successfully created" expect(page).to have_content "Finished" - expect(page).to have_content "30 Aug" + expect(page).to have_content "Aug 2014" # shouldn't be on the page visit plantings_path diff --git a/spec/features/plantings/show_spec.rb b/spec/features/plantings/show_spec.rb index e9d39fca3..c2e01c0a4 100644 --- a/spec/features/plantings/show_spec.rb +++ b/spec/features/plantings/show_spec.rb @@ -22,10 +22,10 @@ describe "Display a planting", :js, :elasticsearch do end context 'Annual with predicted finish' do - let(:planting) { FactoryBot.create :predicatable_planting, planted_at: 1.day.ago } - it { expect(find('.plantingfact--dayssinceplanted')).to have_text '1' } - it { expect(find('.plantingfact--percentagegrown')).to have_text '2%' } - it { expect(find('.plantingfact--planttedat')).to have_text I18n.l(1.day.ago.to_date) } + let(:planting) { FactoryBot.create :predicatable_planting, planted_at: 2.weeks.ago } + it { expect(find('.plantingfact--weekssinceplanted')).to have_text '2' } + it { expect(find('.plantingfact--percentagegrown')).to have_text '28%' } + it { expect(find('.plantingfact--planttedat')).to have_text I18n.l(2.weeks.ago.to_date) } it { expect(find('.plantingfact--harveststitle')).to have_text 'Harvesting' } end diff --git a/spec/features/seeds/adding_seeds_spec.rb b/spec/features/seeds/adding_seeds_spec.rb index e2264eaa2..6ec0b1bd3 100644 --- a/spec/features/seeds/adding_seeds_spec.rb +++ b/spec/features/seeds/adding_seeds_spec.rb @@ -57,11 +57,8 @@ describe "Seeds", :js, :elasticsearch do describe "Adding a seed from crop page" do before do visit crop_path(maize) - click_link "Add maize seeds to stash" - within "form#new_seed" do - expect(page).to have_selector "input[value='maize']" - click_button "Save" - end + click_link "Save seeds" + click_link "Will trade: nowhere" end it { expect(page).to have_content "Successfully added maize seed to your stash" } diff --git a/spec/features/seeds/misc_seeds_spec.rb b/spec/features/seeds/misc_seeds_spec.rb index 53587ede5..a1d047daf 100644 --- a/spec/features/seeds/misc_seeds_spec.rb +++ b/spec/features/seeds/misc_seeds_spec.rb @@ -19,6 +19,7 @@ describe "seeds", js: true do describe "button on front page to add seeds" do before do visit root_path + click_link 'Record' click_link(href: new_seed_path) end @@ -29,7 +30,7 @@ describe "seeds", js: true do describe "Clicking link to owner's profile" do before do visit member_seeds_path(member) - click_link "View #{member}'s profile >>" + click_link "View Owners Profile" end it { expect(current_path).to eq member_path(member) } diff --git a/spec/features/shared_examples/append_date.rb b/spec/features/shared_examples/append_date.rb index 8dc283c22..2680dac30 100644 --- a/spec/features/shared_examples/append_date.rb +++ b/spec/features/shared_examples/append_date.rb @@ -1,5 +1,6 @@ shared_examples "append date" do let(:this_month) { Time.zone.today.strftime("%b") } + let(:this_year) { Time.zone.today.year } before { visit path } @@ -13,7 +14,7 @@ shared_examples "append date" do end end it { expect(page).to have_content "Finished" } - it { expect(page).to have_content "21 #{this_month}" } + it { expect(page).to have_content "#{this_month} #{this_year}" } end describe "Confirming without selecting date" do diff --git a/spec/views/photos/index.html.haml_spec.rb b/spec/views/photos/index.html.haml_spec.rb index f3eae4739..ef058e822 100644 --- a/spec/views/photos/index.html.haml_spec.rb +++ b/spec/views/photos/index.html.haml_spec.rb @@ -17,6 +17,6 @@ describe "photos/index" do it "renders a gallery of photos" do render assert_select ".photo-card", count: 2 - assert_select "img", count: 2 + assert_select "img.img-card", count: 2 end end