diff --git a/.gitignore b/.gitignore index 75fe283a..2a4f41ce 100755 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ client/js/nonprofits/donate/plugins-enabled .DS_Store +/postgres-data # Ignore bundler config /.bundle @@ -62,4 +63,4 @@ javascripts/api !public/css/donate-button.css !public/css/donate-button.v2.css !public/svgs -!public/svgs/* \ No newline at end of file +!public/svgs/* diff --git a/app/assets/stylesheets/campaigns/custom_layout/safety_around_water.css.scss b/app/assets/stylesheets/campaigns/custom_layout/safety_around_water.css.scss new file mode 100644 index 00000000..0be0266f --- /dev/null +++ b/app/assets/stylesheets/campaigns/custom_layout/safety_around_water.css.scss @@ -0,0 +1,78 @@ +@import 'mixins'; +@import 'common/fundraisers'; + +button, a.js-contributeButton { + background: #01a490 !important; +} + +main a.button { + background: #0089d0 !important; + color: white; +} + +main .button.edit, main .button--tiny.edit { + color: white; +} + +main { + width: 1200px; + margin: auto; +} + +main > header { + display: flex; + justify-content: center; + align-items: center; + margin: auto; +} + +body > .ymca-banner { + margin: auto; + width: 100vw; + height: 120px; + background-color: #01a490; +} + +main > header div.fundraisingHeader--image-container { + background-position: 0 -80px; +} + +img.fundraisingHeader--image-aspectRatio { + width: 1200px; + height: 500px; +} + +main > .container { + max-width: none; + margin-top: 15px; +} + +.campaigner-profile { + display: flex; + flex-wrap: nowrap; + align-items: baseline; +} + +.campaigner-profile > figure { + display: flex; + flex-direction: column; + align-items: center; + margin-right: 20px; + align-self: flex-start; +} + +.campaigner-profile > figure > .avatar { + flex-basis: 20%; +} + +.avatar > img { + width: 150px; + height: 150px; + clip-path: circle(50% at center); +} + +.campaigner-profile > figure > figcaption { + flex-basis: 55%; + padding: 15px; + text-align: left; +} diff --git a/app/controllers/campaigns_controller.rb b/app/controllers/campaigns_controller.rb index 21c57919..121e40c8 100644 --- a/app/controllers/campaigns_controller.rb +++ b/app/controllers/campaigns_controller.rb @@ -38,8 +38,12 @@ class CampaignsController < ApplicationController @campaign_background_image = FetchBackgroundImage.with_model(@campaign) - respond_to do |format| - format.html + if @nonprofit.custom_layout.blank? + respond_to do |format| + format.html + end + else + render template: "nonprofits/custom_campaign_layouts/" + @nonprofit.custom_layout end end diff --git a/app/models/campaign.rb b/app/models/campaign.rb index f19278a4..fbc09bb5 100644 --- a/app/models/campaign.rb +++ b/app/models/campaign.rb @@ -13,6 +13,8 @@ class Campaign < ActiveRecord::Base :remove_main_image, # for carrierwave :background_image, :remove_background_image, #bool carrierwave + :custom_banner, + :remove_custom_banner, :published, :video_url, #str :vimeo_video_id, @@ -47,6 +49,7 @@ class Campaign < ActiveRecord::Base mount_uploader :main_image, CampaignMainImageUploader mount_uploader :background_image, CampaignBackgroundImageUploader + mount_uploader :custom_banner, CampaignCustomBannerUploader has_many :donations has_many :charges, through: :donations @@ -60,6 +63,7 @@ class Campaign < ActiveRecord::Base has_many :activities, as: :host, dependent: :destroy belongs_to :profile belongs_to :nonprofit + belongs_to :campaign_template scope :published, -> {where(:published => true)} scope :active, -> {where(:published => true).where("end_datetime IS NULL OR end_datetime >= ?", Date.today)} diff --git a/app/models/campaign_template.rb b/app/models/campaign_template.rb new file mode 100644 index 00000000..fcfe7d63 --- /dev/null +++ b/app/models/campaign_template.rb @@ -0,0 +1,24 @@ +class CampaignTemplate < ActiveRecord::Base + # these are very arbitrary names – some are attrs of campaign, some are not + # might be a good idea to get the default list from settings + CUSTOMIZABLE_ATTR = %i(goal_amount_dollars campaigner_photo reason_for_supporting) + + attr_accessible \ + :template_name, + :name, # refers to campaign name + :tagline, + :goal_amount, + :main_image, + :remove_main_image, # for carrierwave + :video_url, + :vimeo_video_id, + :youtube_video_id, + :summary, + :body + + has_many :campaigns + + def customizable_attribute?(attribute_name) + CUSTOMIZABLE_ATTR.include? attribute_name.to_sym + end +end diff --git a/app/uploaders/campaign_custom_banner_uploader.rb b/app/uploaders/campaign_custom_banner_uploader.rb new file mode 100644 index 00000000..bfc2d652 --- /dev/null +++ b/app/uploaders/campaign_custom_banner_uploader.rb @@ -0,0 +1,39 @@ +class CampaignCustomBannerUploader < CarrierWave::Uploader::Base + + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + + # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: + # include Sprockets::Helpers::RailsHelper + # include Sprockets::Helpers::IsolatedHelper + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/campaigns/#{mounted_as}/#{model.id}" + end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w(jpg jpeg png) + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + + def cache_dir + "#{Rails.root}/tmp/uploads" + end +end diff --git a/app/views/campaigns/_settings_modal.html.erb b/app/views/campaigns/_settings_modal.html.erb index 51838193..199fb825 100644 --- a/app/views/campaigns/_settings_modal.html.erb +++ b/app/views/campaigns/_settings_modal.html.erb @@ -92,6 +92,21 @@ + <% if @nonprofit.custom_layout %> +
+ +
+
+ +

Custom image at the very top of the campaign page

+
+ Edit + +
+
+
+ <% end %> +
@@ -141,7 +156,7 @@ <% end %>
- + > diff --git a/app/views/campaigns/show.html.erb b/app/views/campaigns/show.html.erb index 0fb8f954..6218ffa3 100644 --- a/app/views/campaigns/show.html.erb +++ b/app/views/campaigns/show.html.erb @@ -84,7 +84,7 @@ Manage Gift Options <% end %> - +
@@ -141,4 +141,3 @@ <%= render 'components/share_modal', name: @campaign.name, type: 'campaign' %> <%= render 'common/email_share_modal', fundraiser: @campaign.name, fundraiser_url: @url %> - diff --git a/app/views/nonprofits/custom_campaign_layouts/safety_around_water.html.erb b/app/views/nonprofits/custom_campaign_layouts/safety_around_water.html.erb new file mode 100644 index 00000000..078fc99f --- /dev/null +++ b/app/views/nonprofits/custom_campaign_layouts/safety_around_water.html.erb @@ -0,0 +1,169 @@ +<%= content_for(:title_prefix) { "#{@campaign.name} - #{@campaign.nonprofit.name} | ".html_safe } %> +<% content_for(:fixed_position_cta_hidden) {'hidden'} %> +<%= content_for(:meta_description) {raw @campaign.summary} %> +<% @brand_color = @nonprofit.brand_color ? @nonprofit.brand_color : nil %> + +<%= content_for :javascripts do %> + + <%= render 'schema', campaign: @campaign, url: @url %> + <%= render 'common/froala' if current_campaign_editor? %> + + <%= IncludeAsset.js '/client/js/campaigns/show/page.js' %> +<% end %> + +<%= content_for :stylesheets do %> + <%= stylesheet_link_tag 'campaigns/show/page' %> + <%= stylesheet_link_tag 'campaigns/edit/page' %> + <%= stylesheet_link_tag 'campaigns/custom_layout/safety_around_water' %> + +<% end %> + +<% content_for :head do %> + +<% end %> + +<%= content_for :facebook_tags do %> + + + +<% end %> + +<%= content_for :twitter_tags do %> + + + +<% end %> + +<% if current_campaign_editor? %> + <%= render 'admin_top_nav' %> +<% end %> + +<%= render '/components/trial_bar' if QueryBillingSubscriptions.currently_in_trial?(@nonprofit.id) %> + +<% hide_title = @campaign.hide_title && @campaign_background_image ? true : false %> +<% css_style = current_campaign_editor? ? "style='margin-top: 0'" : '' %> + +
+ +
+ + <%= render 'components/fundraising_pages/header', + image_url: @campaign_background_image, + is_editor: current_campaign_editor?, + hide_title: @campaign.hide_title && @campaign_background_image, + header_content_partial: 'header_content' %> + + <%= render 'components/preview_mode_notification' %> + +
+
+ <%= render 'campaign_media' %> +
+ +
+ + <% if current_campaign_editor? %> + + + <% end %> + + +
+ + + +
+ +
+ +
+
+
+ /> +
+
+

<%= @campaign.profile.name %>

+

<%= @campaign.profile.city %>

+
+
+ +
+
I am supporting the Y because…
+
+ (customizable reason) +
+ + <% unless current_campaign_editor? %> + + Start Your Own Campaign for <%= @nonprofit.name %> + + <% end %> +
+
+
+ +
+

<%= @campaign.name %>

+ +
+ <%= raw @campaign.body %> +
+ + <% unless @campaign.hide_activity_feed %> +
+ <%= render 'components/activity_feed' %> +
+ <% end %> +
+
+
+ +<% if current_campaign_editor? %> + <%= render 'settings_modal' %> + <%= render 'video_modal' %> + <%= render 'donations/campaign_new_offline_modal' %> + <%= render 'campaign_gift_options/manage_modal'%> + <%= render 'campaign_gift_options/form_modal'%> + <%= render 'components/upload_background_image', + end_point: "/nonprofits/#{@nonprofit.id}/campaigns/#{@campaign.id}", + image_url: @campaign_background_image, + input_name: 'campaign[background_image]' %> + <%= render 'components/custom_receipt_modal', + title: 'Campaign Receipt Message', + type: 'campaign', + path: nonprofit_campaign_path(@nonprofit, @campaign), + key: 'campaign[receipt_message]', + text: @campaign.receipt_message %> + <%= render 'components/duplicate_fundraiser_modal', type: 'campaign' %> +<% end %> + +<%= render 'components/share_modal', name: @campaign.name, type: 'campaign' %> +<%= render 'common/email_share_modal', fundraiser: @campaign.name, fundraiser_url: @url %> diff --git a/client/js/nonprofits/donate/wizard.js b/client/js/nonprofits/donate/wizard.js index 1d4a547f..59c945bd 100644 --- a/client/js/nonprofits/donate/wizard.js +++ b/client/js/nonprofits/donate/wizard.js @@ -27,6 +27,7 @@ renderStyles()(brandedWizard(null)) // pass in a stream of configuration parameters const init = params$ => { + console.log(params$()) var state = { error$: flyd.stream() , loading$: flyd.stream() @@ -99,10 +100,10 @@ const init = params$ => { (ev, params) => { if(!parent) return if(params.redirect) parent.postMessage(`commitchange:redirect:${params.redirect}`, '*') - else if(params.mode !== 'embedded'){ + else if(params.mode !== 'embedded'){ parent.postMessage('commitchange:close', '*'); } else { - if (window.parent) {window.parent.postMessage('commitchange:close', '*');}; + if (window.parent) {window.parent.postMessage('commitchange:close', '*');}; } } , state.clickFinish$, state.params$ ) @@ -193,16 +194,18 @@ const headerDesignation = state => { } const wizardWrapper = state => { - return h('div.wizard-steps.donation-steps', [ - wizard.view(R.merge(state.wizard, { - steps: [ - {name: I18n.t('nonprofits.donate.amount.label'), body: amountStep.view(state.amountStep)} - , {name: I18n.t('nonprofits.donate.info.label'), body: infoStep.view(state.infoStep)} - , {name: I18n.t('nonprofits.donate.payment.label'), body: paymentStep.view(state.paymentStep)} - ] - , followup: followupStep.view(state) - })) - ]) + // return h('div.wizard-steps.donation-steps', [ + // wizard.view(R.merge(state.wizard, { + // steps: [ + // {name: I18n.t('nonprofits.donate.amount.label'), body: amountStep.view(state.amountStep)} + // , {name: I18n.t('nonprofits.donate.info.label'), body: infoStep.view(state.infoStep)} + // , {name: I18n.t('nonprofits.donate.payment.label'), body: paymentStep.view(state.paymentStep)} + // ] + // , followup: followupStep.view(state) + // })) + // ]) + + return h('div.wizard-steps.donation-steps', 'Donation widget should be here.') } module.exports = {view, init} diff --git a/config/routes.rb b/config/routes.rb index a9520158..39f0f3e5 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -147,6 +147,8 @@ Commitchange::Application.routes.draw do resources(:campaign_gift_options, {only: [:index, :show, :create, :update, :destroy]}) do put(:update_order, {on: :collection}) end + + get 'custom_layout', controller: 'campaigns', action: 'custom_layout' end resource(:billing_subscription, {only: [:create]}) do @@ -224,6 +226,7 @@ Commitchange::Application.routes.draw do # Campaigns match ':state_code/:city/:name/campaigns' => 'campaigns#index' match ':state_code/:city/:name/campaigns/:campaign_slug' => 'campaigns#show', :as => :campaign_loc + match ':state_code/:city/:name/campaigns/:campaign_slug/custom_layout' => 'campaigns#custom_layout', :as => :campaign_loc match ':state_code/:city/:name/campaigns/:campaign_slug/supporters' => 'campaigns/supporters#index', :as => :campaign_loc match '/peer-to-peer' => 'campaigns#peer_to_peer' diff --git a/config/settings.yml b/config/settings.yml index c465193b..f657c967 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -20,7 +20,7 @@ default: aws: access_key_id: <%= ENV['AWS_ACCESS_KEY'] %> secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %> - region: test + region: <%= ENV['AWS_REGION'] %> bucket: <%= ENV['S3_BUCKET_NAME'] %> mailer: diff --git a/db/migrate/201810202124316_add_campaign_templates.rb b/db/migrate/201810202124316_add_campaign_templates.rb new file mode 100644 index 00000000..062f37b2 --- /dev/null +++ b/db/migrate/201810202124316_add_campaign_templates.rb @@ -0,0 +1,22 @@ +class AddCampaignTemplates < ActiveRecord::Migration + def change + create_table :campaign_templates do |t| + t.string :template_name, null: false + t.string :name + t.string :tagline + t.integer :goal_amount + t.string :main_image + t.text :video_url + t.string :vimeo_video_id + t.string :youtube_video_id + t.text :summary + t.text :body + + t.timestamps + end + + change_table :campaigns do |t| + t.references :campaign_template + end + end +end diff --git a/db/migrate/201810202124317_add_custom_layout_to_nonprofit.rb b/db/migrate/201810202124317_add_custom_layout_to_nonprofit.rb new file mode 100644 index 00000000..db58866a --- /dev/null +++ b/db/migrate/201810202124317_add_custom_layout_to_nonprofit.rb @@ -0,0 +1,5 @@ +class AddCustomLayoutToNonprofit < ActiveRecord::Migration + def change + add_column :nonprofits, :custom_layout, :string + end +end diff --git a/db/migrate/201810202124318_add_banner_to_campaign.rb b/db/migrate/201810202124318_add_banner_to_campaign.rb new file mode 100644 index 00000000..c1fe6406 --- /dev/null +++ b/db/migrate/201810202124318_add_banner_to_campaign.rb @@ -0,0 +1,5 @@ +class AddBannerToCampaign < ActiveRecord::Migration + def change + add_column :campaigns, :custom_banner, :string + end +end diff --git a/db/structure.sql b/db/structure.sql index 0844371c..b146ebc2 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2,8 +2,13 @@ -- PostgreSQL database dump -- +<<<<<<< HEAD -- Dumped from database version 9.6.5 -- Dumped by pg_dump version 9.6.10 +======= +-- Dumped from database version 9.6.8 +-- Dumped by pg_dump version 9.6.8 +>>>>>>> Add CampaignTemplate SET statement_timeout = 0; SET lock_timeout = 0; @@ -355,6 +360,46 @@ CREATE SEQUENCE public.campaign_gifts_id_seq ALTER SEQUENCE public.campaign_gifts_id_seq OWNED BY public.campaign_gifts.id; +-- +-- Name: campaign_templates; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.campaign_templates ( + id integer NOT NULL, + template_name character varying(255) NOT NULL, + name character varying(255), + tagline character varying(255), + goal_amount integer, + main_image character varying(255), + video_url text, + vimeo_video_id character varying(255), + youtube_video_id character varying(255), + summary text, + body text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: campaign_templates_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.campaign_templates_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: campaign_templates_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.campaign_templates_id_seq OWNED BY public.campaign_templates.id; + + -- -- Name: campaigns; Type: TABLE; Schema: public; Owner: - -- @@ -392,7 +437,8 @@ CREATE TABLE public.campaigns ( hide_custom_amounts boolean, show_recurring_amount boolean DEFAULT false, end_datetime timestamp without time zone, - external_identifier character varying(255) + external_identifier character varying(255), + campaign_template_id integer ); @@ -1412,7 +1458,8 @@ CREATE TABLE public.nonprofits ( card_failure_message_bottom text, fields_needed text, autocomplete_supporter_address boolean DEFAULT false, - currency character varying(255) DEFAULT 'usd'::character varying + currency character varying(255) DEFAULT 'usd'::character varying, + custom_layout character varying(255) ); @@ -2305,6 +2352,13 @@ ALTER TABLE ONLY public.campaign_gift_options ALTER COLUMN id SET DEFAULT nextva ALTER TABLE ONLY public.campaign_gifts ALTER COLUMN id SET DEFAULT nextval('public.campaign_gifts_id_seq'::regclass); +-- +-- Name: campaign_templates id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.campaign_templates ALTER COLUMN id SET DEFAULT nextval('public.campaign_templates_id_seq'::regclass); + + -- -- Name: campaigns id; Type: DEFAULT; Schema: public; Owner: - -- @@ -2690,6 +2744,14 @@ ALTER TABLE ONLY public.campaign_gifts ADD CONSTRAINT campaign_gifts_pkey PRIMARY KEY (id); +-- +-- Name: campaign_templates campaign_templates_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.campaign_templates + ADD CONSTRAINT campaign_templates_pkey PRIMARY KEY (id); + + -- -- Name: campaigns campaigns_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -4347,3 +4409,7 @@ INSERT INTO schema_migrations (version) VALUES ('20181002160627'); INSERT INTO schema_migrations (version) VALUES ('20181003212559'); +INSERT INTO schema_migrations (version) VALUES ('201810202124316'); + +INSERT INTO schema_migrations (version) VALUES ('201810202124317'); +