diff --git a/app/controllers/impact_stories_controller.rb b/app/controllers/impact_stories_controller.rb new file mode 100644 index 00000000..14d2f49b --- /dev/null +++ b/app/controllers/impact_stories_controller.rb @@ -0,0 +1,45 @@ +class ImpactStoriesController < ApplicationController + before_action :authenticate_user! + + def index + @impact_stories = current_partner.impact_stories.sort_by(&:created_at).reverse + end + + def show + @impact_story = current_partner.impact_stories.find(params[:id]) + end + + def new + @impact_story = current_partner.impact_stories.new + end + + def create + @impact_story = current_partner.impact_stories.new(impact_story_params) + + if @impact_story.save + redirect_to @impact_story, notice: "Impact Story was successfully created." + else + render :new + end + end + + def edit + @impact_story = current_partner.impact_stories.find(params[:id]) + end + + def update + @impact_story = current_partner.impact_stories.find(params[:id]) + + if @impact_story.update(impact_story_params) + redirect_to @impact_story, notice: "Impact Story was successfully updated." + else + render :edit + end + end + + private + + def impact_story_params + params.require(:impact_story).permit(:title, :content) + end +end diff --git a/app/models/impact_story.rb b/app/models/impact_story.rb new file mode 100644 index 00000000..bb3e22c6 --- /dev/null +++ b/app/models/impact_story.rb @@ -0,0 +1,21 @@ +# == Schema Information +# +# Table name: impact_stories +# +# id :bigint(8) not null, primary key +# partner_id :bigint(8) +# title :string not null +# content :text not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class ImpactStory < ApplicationRecord + belongs_to :partner + + validates :title, :content, presence: true + + def blurb(limit) + content.truncate(limit, separator: ' ') + end +end diff --git a/app/models/partner.rb b/app/models/partner.rb index 5272d70f..15ca7fe2 100644 --- a/app/models/partner.rb +++ b/app/models/partner.rb @@ -99,6 +99,8 @@ class Partner < ApplicationRecord has_many :children, through: :families has_many :authorized_family_members, through: :families + has_many :impact_stories, dependent: :destroy + has_many :partner_requests, dependent: :destroy has_many :family_requests, dependent: :destroy has_one :partner_form, primary_key: :diaper_bank_id, foreign_key: :diaper_bank_id, dependent: :destroy diff --git a/app/views/impact_stories/_form.html.erb b/app/views/impact_stories/_form.html.erb new file mode 100644 index 00000000..7462c58e --- /dev/null +++ b/app/views/impact_stories/_form.html.erb @@ -0,0 +1,28 @@ +
+
+
+ +
+ +
+ + +
+ <%= simple_form_for impact_story, html: {role: 'form', class: 'form-horizontal'} do |f| %> + <%= f.input :title, label: "Story Title", class: "form-control", wrapper: :input_group %> + + <%= f.text_area :content, label: "Story Content", class: "form-control", wrapper: :input_group %> + + + <% end %> +
+ +
+

We're working on adding image upload. Watch this space for updates!

+
+
+ +
+
\ No newline at end of file diff --git a/app/views/impact_stories/_list.html.erb b/app/views/impact_stories/_list.html.erb new file mode 100644 index 00000000..f8d2e2d9 --- /dev/null +++ b/app/views/impact_stories/_list.html.erb @@ -0,0 +1,21 @@ + + + + + + + + + + + <% @impact_stories.each do |story| %> + + + + + + + <% end %> + +
Story TitleDate CreatedContent +
<%= story.title %><%= story.created_at.strftime("%B %-d %Y") %><%= story.blurb(40) %><%= link_to 'View Story', story, class: "btn btn-sm btn-info pull-right" %><%= link_to 'Edit Story Details', edit_impact_story_path(story), class: "btn btn-sm btn-success pull-right" %>
diff --git a/app/views/impact_stories/edit.html.erb b/app/views/impact_stories/edit.html.erb new file mode 100644 index 00000000..bc9bfa67 --- /dev/null +++ b/app/views/impact_stories/edit.html.erb @@ -0,0 +1,27 @@ +
+
+
+
+ <% content_for :title, "Impact Story - #{current_partner.name}" %> +

   + Edit Impact Story + for <%= current_partner.name %> +

+
+
+ +
+
+
+
+ +<%= render 'form', impact_story: @impact_story %> \ No newline at end of file diff --git a/app/views/impact_stories/index.html.erb b/app/views/impact_stories/index.html.erb new file mode 100644 index 00000000..33277f72 --- /dev/null +++ b/app/views/impact_stories/index.html.erb @@ -0,0 +1,64 @@ + +
+
+
+
+ <% content_for :title, "Impact Stories - #{current_partner.name}" %> +

   + Impact Stories + for <%= current_partner.name %> +

+
+
+ +
+
+
+
+ +
+
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+
+ +
+
+
+ <%= render( + partial: 'impact_stories/list', + locals: {impact_stories: @impact_stories} + ) %> +
+
+
+ +
+
+
+
diff --git a/app/views/impact_stories/new.html.erb b/app/views/impact_stories/new.html.erb new file mode 100644 index 00000000..e99f3a91 --- /dev/null +++ b/app/views/impact_stories/new.html.erb @@ -0,0 +1,25 @@ +
+
+
+
+ <% content_for :title, "Impact Story - #{current_partner.name}" %> +

   + New Impact Story + for <%= current_partner.name %> +

+
+
+ +
+
+
+
+ +<%= render 'form', impact_story: @impact_story %> \ No newline at end of file diff --git a/app/views/impact_stories/show.html.erb b/app/views/impact_stories/show.html.erb new file mode 100644 index 00000000..b4794d1c --- /dev/null +++ b/app/views/impact_stories/show.html.erb @@ -0,0 +1,49 @@ +
+
+
+
+ <% content_for :title, "Impact Stories - #{current_partner.name}" %> +

   + Impact Story Details + for <%= current_partner.name %> +

+
+
+ +
+
+
+
+ +
+
+
+
+
+
Story Information +
+
+
+
Story Title:
+
<%= @impact_story.title %>
+ +
Story Content:
+
<%= simple_format(h(@impact_story.content)) %>
+
+
+ +
+
+
+
+
diff --git a/app/views/layouts/_sidebar.html.erb b/app/views/layouts/_sidebar.html.erb index 61ce9690..aaf6f7a9 100644 --- a/app/views/layouts/_sidebar.html.erb +++ b/app/views/layouts/_sidebar.html.erb @@ -41,5 +41,11 @@ <% end %> + \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index d3ff5a2e..6f3bd4cd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -66,6 +66,8 @@ end end + resources :impact_stories, except: [:destroy] + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html get "pages/:name", to: "static#page", as: "static_page" root "static#index" diff --git a/db/migrate/20200905195722_create_impact_stories.rb b/db/migrate/20200905195722_create_impact_stories.rb new file mode 100644 index 00000000..0d590011 --- /dev/null +++ b/db/migrate/20200905195722_create_impact_stories.rb @@ -0,0 +1,11 @@ +class CreateImpactStories < ActiveRecord::Migration[6.0] + def change + create_table :impact_stories do |t| + t.string :title, null: false + t.text :content, null: false + t.references :partner, index: true, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 307fd9c3..8b4ac860 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: 2020_05_18_010905) do +ActiveRecord::Schema.define(version: 2020_09_05_195722) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -119,6 +119,15 @@ t.index ["feature_key", "key", "value"], name: "index_flipper_gates_on_feature_key_and_key_and_value", unique: true end + create_table "impact_stories", force: :cascade do |t| + t.string "title", null: false + t.text "content", null: false + t.bigint "partner_id" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["partner_id"], name: "index_impact_stories_on_partner_id" + end + create_table "item_requests", force: :cascade do |t| t.string "name" t.string "quantity" @@ -273,6 +282,7 @@ add_foreign_key "child_item_requests", "item_requests" add_foreign_key "children", "families" add_foreign_key "families", "partners" + add_foreign_key "impact_stories", "partners" add_foreign_key "item_requests", "partner_requests" add_foreign_key "users", "partners" end diff --git a/spec/factories/impact_stories.rb b/spec/factories/impact_stories.rb new file mode 100644 index 00000000..72fdd39f --- /dev/null +++ b/spec/factories/impact_stories.rb @@ -0,0 +1,19 @@ +# == Schema Information +# +# Table name: impact_stories +# +# id :bigint(8) not null, primary key +# partner_id :bigint(8) +# title :string not null +# content :text not null +# created_at :datetime not null +# updated_at :datetime not null +# + +FactoryBot.define do + factory :impact_story do + title { Faker::Lorem.word } + content { Faker::Lorem.paragraph } + partner + end +end diff --git a/spec/features/impact_story_feature_spec.rb b/spec/features/impact_story_feature_spec.rb new file mode 100644 index 00000000..a70fec43 --- /dev/null +++ b/spec/features/impact_story_feature_spec.rb @@ -0,0 +1,35 @@ +require "rails_helper" + +describe ImpactStory, type: :feature, include_shared: true, js: true do + let(:partner) { create(:partner, :verified, id: 3) } + let(:user) { create(:user, partner: partner) } + + before do + Flipper[:impact_story_requests].enable(partner) + sign_in(user) + visit(root_path) + end + + scenario "User can see a list of impact stories" do + diaper_type = "Magic diaper" + stub_request(:any, "#{ENV["DIAPERBANK_ENDPOINT"]}/partner_requests/#{partner.id}") + .to_return(body: [{ id: 1, name: diaper_type }].to_json, status: 200) + + impact_stories = [ + create(:impact_story, title: "Title1", content: "Content 1", partner: partner), + create(:impact_story, title: "Title2", content: "Content 2", partner: partner) + ].reverse + + click_link "Share Our Impact" + impact_stories.each.with_index do |story, index| + within "tbody" do + expect(find("tr:nth-child(#{index + 1}) td:nth-child(1)")) + .to have_text(story.title) + expect(find("tr:nth-child(#{index + 1}) td:nth-child(2)")) + .to have_text(story.created_at.strftime("%B %-d %Y")) + expect(find("tr:nth-child(#{index + 1}) td:nth-child(3)")) + .to have_text(story.content) + end + end + end +end diff --git a/spec/models/impact_story_spec.rb b/spec/models/impact_story_spec.rb new file mode 100644 index 00000000..abba4129 --- /dev/null +++ b/spec/models/impact_story_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe ImpactStory, type: :model do + describe 'associations' do + it { should belong_to(:partner).class_name('Partner') } + end + + describe 'validations' do + it { should validate_presence_of(:title) } + it { should validate_presence_of(:content) } + end + + describe '#blurb' do + subject { impact_story.blurb(10) } + let(:impact_story) { create(:impact_story, title: Faker::Lorem.word, content: Faker::Lorem.paragraph) } + + it "returns truncates the content to less than or equal to 10 characters" do + expect(subject.length).to be <= 20 + end + end +end diff --git a/spec/requests/impact_stories_request_spec.rb b/spec/requests/impact_stories_request_spec.rb new file mode 100644 index 00000000..2a79a7c2 --- /dev/null +++ b/spec/requests/impact_stories_request_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +RSpec.describe "ImpactStories", type: :request do + let(:partner) { create(:partner) } + let!(:user) { create(:user, partner: partner) } + + before do + sign_in user + end + + describe "GET #index" do + it "return http sucess" do + get impact_stories_path + + expect(response).to have_http_status(:ok) + end + end + + describe "GET #new" do + it "should return status code 200" do + get new_impact_story_path + + expect(response).to have_http_status :ok + end + end + + describe "POST #create" do + it "should create and redirect to impact_story_path" do + post impact_stories_path, params: { impact_story: attributes_for(:impact_story) } + + impact_story = ImpactStory.select(:id).last + + expect(response).to redirect_to(impact_story_path(impact_story.id)) + expect(request.flash[:notice]).to eql "Impact Story was successfully created." + end + end + + describe "PUT #update" do + let(:impact_story) { create(:impact_story, partner: partner) } + + it "should update and redirect to impact_story_path" do + put impact_story_path(impact_story), params: { impact_story: attributes_for(:impact_story) } + + expect(response).to redirect_to(impact_story_path(impact_story.id)) + expect(request.flash[:notice]).to eql "Impact Story was successfully updated." + end + end +end