mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-10-01 02:14:28 -04:00
Add a gallery page of a member's past gardens
/members/:slug/gardens/past shows their inactive gardens as photo cards: when each was in use, how many plantings, and the crops grown in it. The owner (or a collaborator) can mark a garden active again from its card. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1e80abb70c
commit
dcf59ff4e7
8 files changed
+186
No files matched your search
@@ -0,0 +1,38 @@
|
||||
// A member's past gardens: a gallery of cards, a photo and what was grown.
|
||||
|
||||
.past-garden-card {
|
||||
overflow: hidden;
|
||||
|
||||
.card-img-top {
|
||||
display: block;
|
||||
width: 100%;
|
||||
aspect-ratio: 3 / 2;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.past-garden-meta {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.past-garden-crops {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
margin: 0 0.5rem 0.5rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.past-garden-more {
|
||||
align-self: center;
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
@import "notifications";
|
||||
@import "plantings";
|
||||
@import "garden_cards";
|
||||
@import "past_gardens";
|
||||
@import "photos";
|
||||
@import "posts";
|
||||
@import "seeds";
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class GardensController < DataController
|
||||
# Anyone can look at a member's past gardens, as they can their current ones.
|
||||
skip_before_action :authenticate_member!, only: :past
|
||||
skip_load_and_authorize_resource only: :past
|
||||
|
||||
def index
|
||||
@owner = Member.find_by!(slug: params[:member_slug]) if params[:member_slug].present?
|
||||
@show_all = params[:all] == '1'
|
||||
@@ -17,6 +21,17 @@ class GardensController < DataController
|
||||
respond_with(@gardens)
|
||||
end
|
||||
|
||||
# A member's gardens that are no longer active, as a gallery of what they grew.
|
||||
def past
|
||||
@owner = Member.confirmed.find_by!(slug: params[:member_slug])
|
||||
owned = Garden.inactive.where(owner: @owner)
|
||||
collaborating = Garden.inactive.where(id: GardenCollaborator.where(member: @owner).select(:garden_id))
|
||||
@gardens = owned.or(collaborating)
|
||||
.includes(:owner, plantings: { crop: { parent: :parent } })
|
||||
.order(updated_at: :desc)
|
||||
.paginate(page: params[:page], per_page: 12)
|
||||
end
|
||||
|
||||
def show
|
||||
@current_plantings = @garden.plantings.current.where.not(failed: true).includes(:crop, :owner).order(planted_at: :desc)
|
||||
@current_activities = @garden.activities.current.includes(:owner).order(created_at: :desc)
|
||||
|
||||
@@ -11,6 +11,15 @@ module GardensHelper
|
||||
}
|
||||
end
|
||||
|
||||
# "2022–2024 · 12 plantings": when a past garden was in use, by its plantings.
|
||||
def garden_history_summary(garden)
|
||||
plantings = garden.plantings.to_a
|
||||
years = plantings.filter_map { |planting| planting.planted_at&.year }
|
||||
years = [garden.created_at.year] if years.empty?
|
||||
range = years.min == years.max ? years.min.to_s : "#{years.min}–#{years.max}"
|
||||
"#{range} · #{pluralize(plantings.size, 'planting')}"
|
||||
end
|
||||
|
||||
def display_garden_description(garden)
|
||||
if garden.description.nil?
|
||||
"no description provided."
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
- crops = garden.plantings.map(&:crop).uniq
|
||||
- shown = 8
|
||||
.card.h-100.past-garden-card
|
||||
= link_to garden_path(garden) do
|
||||
= image_tag garden_image_path(garden), alt: "Image of #{garden.name}", class: 'card-img-top'
|
||||
.card-body
|
||||
%h2.h5.card-title= link_to garden.name, garden_path(garden)
|
||||
%p.past-garden-meta= garden_history_summary(garden)
|
||||
- if garden.description.present?
|
||||
%p.card-text= truncate(garden.description, length: 130, separator: ' ', omission: '...')
|
||||
- if crops.any?
|
||||
%ul.past-garden-crops.list-unstyled{'aria-label': 'Grown here'}
|
||||
- crops.first(shown).each do |crop|
|
||||
%li
|
||||
= link_to crop_path(crop) do
|
||||
.chip.crop-chip
|
||||
= crop_icon(crop)
|
||||
= crop.name
|
||||
- if crops.size > shown
|
||||
%li.past-garden-more= "and #{crops.size - shown} more"
|
||||
- if can?(:edit, garden)
|
||||
.card-footer
|
||||
= garden_mark_active_button(garden, classes: 'btn btn-sm btn-outline-success')
|
||||
@@ -0,0 +1,31 @@
|
||||
- content_for :title, "#{@owner}'s past gardens"
|
||||
|
||||
- content_for :breadcrumbs do
|
||||
%li.breadcrumb-item= link_to 'Gardens', gardens_path
|
||||
%li.breadcrumb-item= link_to "#{@owner}'s gardens", member_gardens_path(@owner)
|
||||
%li.breadcrumb-item.active= link_to 'Past gardens', member_past_gardens_path(@owner)
|
||||
|
||||
%h1 #{@owner}'s past gardens
|
||||
|
||||
.row
|
||||
.col-md-2
|
||||
%small
|
||||
%a{href: "#content"}
|
||||
Skip to main content
|
||||
= render 'layouts/nav', model: Garden
|
||||
= link_to "Current gardens", member_gardens_path(@owner), class: 'nav-link'
|
||||
%hr/
|
||||
= render @owner
|
||||
|
||||
.col-md-10#content
|
||||
- if @gardens.empty?
|
||||
%p
|
||||
There are no past gardens to show.
|
||||
- if @owner == current_member
|
||||
A garden you mark as inactive will appear here.
|
||||
- else
|
||||
%p.lead Gardens that are no longer in use, and what was grown in them.
|
||||
.row.row-cols-1.row-cols-sm-2.row-cols-lg-3.g-4
|
||||
- @gardens.each do |garden|
|
||||
.col= render 'gardens/past_card', garden: garden
|
||||
.mt-3= will_paginate @gardens
|
||||
@@ -115,6 +115,8 @@ Rails.application.routes.draw do
|
||||
resources :timeline
|
||||
|
||||
resources :members, param: :slug do
|
||||
# Before the gardens resource, so "past" isn't taken for a garden's id.
|
||||
get 'gardens/past' => 'gardens#past', as: :past_gardens
|
||||
resources :gardens
|
||||
resources :seeds
|
||||
resources :plantings
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe "A member's past gardens" do
|
||||
let(:owner) { create(:member, login_name: 'gardener') }
|
||||
let(:tomato) { create(:tomato) }
|
||||
let!(:retired) { create(:inactive_garden, owner: owner, name: 'Old plot', description: 'Where it all began') }
|
||||
let!(:current) { create(:garden, owner: owner, name: 'Current plot') }
|
||||
|
||||
before do
|
||||
create(:planting, owner: owner, garden: retired, crop: tomato, planted_at: Date.new(2021, 10, 1))
|
||||
create(:planting, owner: owner, garden: retired, crop: create(:maize), planted_at: Date.new(2023, 2, 1))
|
||||
end
|
||||
|
||||
context 'when nobody is signed in' do
|
||||
before { visit member_past_gardens_path(owner) }
|
||||
|
||||
it 'shows only the inactive gardens, with when they were used and what was grown' do
|
||||
expect(page).to have_link 'Old plot', href: garden_path(retired)
|
||||
expect(page).to have_no_text 'Current plot'
|
||||
expect(page).to have_text '2021–2023 · 2 plantings'
|
||||
expect(page).to have_text 'Where it all began'
|
||||
expect(page).to have_link tomato.name, href: crop_path(tomato)
|
||||
end
|
||||
|
||||
it 'does not offer to reactivate' do
|
||||
expect(page).to have_no_link 'Mark as active'
|
||||
end
|
||||
|
||||
it 'links back to the current gardens' do
|
||||
expect(page).to have_link 'Current gardens', href: member_gardens_path(owner)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the owner is signed in' do
|
||||
include_context 'signed in member'
|
||||
let(:owner) { member }
|
||||
|
||||
before { visit member_past_gardens_path(owner) }
|
||||
|
||||
it 'lets them reactivate a garden' do
|
||||
click_link 'Mark as active'
|
||||
|
||||
expect(retired.reload).to be_active
|
||||
end
|
||||
end
|
||||
|
||||
context "when someone else's past gardens" do
|
||||
include_context 'signed in member'
|
||||
|
||||
before { visit member_past_gardens_path(owner) }
|
||||
|
||||
it 'does not let a signed in visitor reactivate them' do
|
||||
expect(page).to have_link 'Old plot'
|
||||
expect(page).to have_no_link 'Mark as active'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no past gardens' do
|
||||
before { visit member_past_gardens_path(create(:member)) }
|
||||
|
||||
it 'says so' do
|
||||
expect(page).to have_text 'There are no past gardens to show.'
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user