diff --git a/.babelrc b/.babelrc index ded31c0d80..75e4c04e4a 100644 --- a/.babelrc +++ b/.babelrc @@ -1,18 +1,26 @@ { "presets": [ - ["env", { - "modules": false, - "targets": { - "browsers": "> 1%", - "uglify": true - }, - "useBuiltIns": true - }] + [ + "env", + { + "modules": false, + "targets": { + "browsers": "> 1%", + "uglify": true + }, + "useBuiltIns": true + } + ], + "react" ], - "plugins": [ "syntax-dynamic-import", "transform-object-rest-spread", - ["transform-class-properties", { "spec": true }] + [ + "transform-class-properties", + { + "spec": true + } + ] ] } diff --git a/.gitignore b/.gitignore index bcc7cb5fd3..dbb56137e9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ dump.rdb yarn-error.log .DS_Store +# Ignore assets stored in /storage +/storage + # Ignore Byebug command history file. .byebug_history /ssl/ diff --git a/Gemfile b/Gemfile index 25b0df6111..df4a3f49fa 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,9 @@ gem "attr_encrypted", "~> 3.1.0" # Integration with Matomo Piwik gem 'autometal-piwik', :require => 'piwik', git: "https://github.com/matomo-org/piwik-ruby-api.git", branch: "master" +# Use AWS gem for s3 uploads +gem 'aws-sdk-s3', require: false + gem "bootstrap", "~> 4.1.1" # browser details @@ -49,6 +52,9 @@ gem "nokogiri", "~> 1.8.4" # Open Graph tag gem "meta-tags" +# Image conversion library +gem 'mini_magick' + # Oauth client for google / youtube gem "omniauth-google-oauth2", "~> 0.5.2" diff --git a/Gemfile.lock b/Gemfile.lock index bae4158ab7..e3f22771fa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -78,6 +78,21 @@ GEM encryptor (~> 3.0.0) autoprefixer-rails (9.0.0) execjs + aws-eventstream (1.0.1) + aws-partitions (1.104.0) + aws-sdk-core (3.27.0) + aws-eventstream (~> 1.0) + aws-partitions (~> 1.0) + aws-sigv4 (~> 1.0) + jmespath (~> 1.0) + aws-sdk-kms (1.9.0) + aws-sdk-core (~> 3, >= 3.26.0) + aws-sigv4 (~> 1.0) + aws-sdk-s3 (1.19.0) + aws-sdk-core (~> 3, >= 3.26.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.0) + aws-sigv4 (1.0.3) bcrypt (3.1.12) bindex (0.5.0) bootstrap (4.1.3) @@ -106,7 +121,7 @@ GEM activesupport childprocess (0.9.0) ffi (~> 1.0, >= 1.0.11) - chromedriver-helper (1.2.0) + chromedriver-helper (2.0.1) archive-zip (~> 0.10) nokogiri (~> 1.8) chunky_png (1.3.10) @@ -170,6 +185,7 @@ GEM jbuilder (2.7.0) activesupport (>= 4.2.0) multi_json (>= 1.2) + jmespath (1.4.0) json (2.1.0) jsonapi-renderer (0.2.0) jwt (1.5.6) @@ -196,6 +212,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2018.0812) mimemagic (0.3.2) + mini_magick (4.9.2) mini_mime (1.0.0) mini_portile2 (2.3.0) minitest (5.11.3) @@ -457,6 +474,7 @@ DEPENDENCIES api-pagination attr_encrypted (~> 3.1.0) autometal-piwik! + aws-sdk-s3 bootstrap (~> 4.1.1) brakeman browser @@ -476,6 +494,7 @@ DEPENDENCIES listen (~> 3.0.5) lograge (~> 0.4) meta-tags + mini_magick minitest-rails-capybara (~> 3.0.1) mocha newrelic_rpm (~> 3.16) diff --git a/app/assets/images/.DS_Store b/app/assets/images/.DS_Store deleted file mode 100644 index 8fe46f6bdc..0000000000 Binary files a/app/assets/images/.DS_Store and /dev/null differ diff --git a/app/assets/images/bg_bats.svg b/app/assets/images/bg_bats.svg new file mode 100644 index 0000000000..b0318e87a0 --- /dev/null +++ b/app/assets/images/bg_bats.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/bg_hearts.svg b/app/assets/images/bg_hearts.svg new file mode 100644 index 0000000000..30f21597b0 --- /dev/null +++ b/app/assets/images/bg_hearts.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/brave-lion@3x.jpg b/app/assets/images/brave-lion@3x.jpg new file mode 100644 index 0000000000..59fec8c30c Binary files /dev/null and b/app/assets/images/brave-lion@3x.jpg differ diff --git a/app/assets/images/camera.png b/app/assets/images/camera.png new file mode 100644 index 0000000000..746c40375b Binary files /dev/null and b/app/assets/images/camera.png differ diff --git a/app/assets/images/camera@2x.png b/app/assets/images/camera@2x.png new file mode 100644 index 0000000000..cb0e904c4e Binary files /dev/null and b/app/assets/images/camera@2x.png differ diff --git a/app/assets/images/camera@3x.png b/app/assets/images/camera@3x.png new file mode 100644 index 0000000000..6eb8b80f79 Binary files /dev/null and b/app/assets/images/camera@3x.png differ diff --git a/app/assets/images/icn-donation-jar@1x.png b/app/assets/images/icn-donation-jar@1x.png new file mode 100644 index 0000000000..c1f26a67e3 Binary files /dev/null and b/app/assets/images/icn-donation-jar@1x.png differ diff --git a/app/assets/images/icn-donation-jar@2x.png b/app/assets/images/icn-donation-jar@2x.png new file mode 100644 index 0000000000..9e1598b517 Binary files /dev/null and b/app/assets/images/icn-donation-jar@2x.png differ diff --git a/app/assets/images/icn-donation-jar@3x.png b/app/assets/images/icn-donation-jar@3x.png new file mode 100644 index 0000000000..d452cad983 Binary files /dev/null and b/app/assets/images/icn-donation-jar@3x.png differ diff --git a/app/assets/images/icn-editPhoto.svg b/app/assets/images/icn-editPhoto.svg new file mode 100644 index 0000000000..97f52cd53b --- /dev/null +++ b/app/assets/images/icn-editPhoto.svg @@ -0,0 +1,18 @@ + + + + camera2 + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/images/san_francisco.jpg b/app/assets/images/san_francisco.jpg new file mode 100644 index 0000000000..384e779176 Binary files /dev/null and b/app/assets/images/san_francisco.jpg differ diff --git a/app/assets/stylesheets/pages/home.scss b/app/assets/stylesheets/pages/home.scss index 3369b34058..e2a414d308 100644 --- a/app/assets/stylesheets/pages/home.scss +++ b/app/assets/stylesheets/pages/home.scss @@ -1,3 +1,55 @@ +.camera-background { + background-size: 60px 47px; + width: 60px; + height: 47px; + background-image: url(asset-path("camera@2x.png")); + background-color: transparent; + border-style: none; +} + +#icn-donation-jar { + margin-bottom: 30px; +} + +.brave-rewards-banner { + &--background { + &-label { + display: block; + margin-left: -4px; + margin-top: 5px; + font-size: 16px; + } + + &-camera { + margin-left: 46%; + margin-top: -60px; + } + } + &--logo { + &-parent { + position: relative; + } + + &-label { + display: block; + margin-left: -4px; + margin-top: 5px; + font-size: 16px; + } + + &-no-attachment { + margin-left: 30%; + position: absolute; + } + + &-camera { + margin-left: 30%; + margin-top: 30%; + position: absolute; + } + } +} + .nav { display: block; diff --git a/app/controllers/banners_controller.rb b/app/controllers/banners_controller.rb new file mode 100644 index 0000000000..c55add06d2 --- /dev/null +++ b/app/controllers/banners_controller.rb @@ -0,0 +1,5 @@ +class BannersController < ApplicationController + def new + @publisher_id = current_publisher.id + end +end diff --git a/app/controllers/publishers/site_banners_controller.rb b/app/controllers/publishers/site_banners_controller.rb new file mode 100644 index 0000000000..f3b87c7cc5 --- /dev/null +++ b/app/controllers/publishers/site_banners_controller.rb @@ -0,0 +1,105 @@ +class Publishers::SiteBannersController < ApplicationController + include ImageConversionHelper + before_action :authenticate_publisher! + + MAX_IMAGE_SIZE = 10_000_000 + + def new + @site_banner = current_publisher.site_banner || SiteBanner.new + end + + def create + site_banner = current_publisher.site_banner || SiteBanner.new + donation_amounts = JSON.parse(params[:donation_amounts]) + site_banner.update( + publisher_id: current_publisher.id, + title: params[:title], + donation_amounts: donation_amounts, + default_donation: donation_amounts.second, + social_links: params[:social_links].present? ? JSON.parse(params[:social_links]) : {}, + description: params[:description] + ) + head :ok + end + + def fetch + site_banner = current_publisher.site_banner + data = JSON.parse(site_banner.to_json) + data[:backgroundImage] = current_publisher.site_banner.read_only_react_property[:backgroundUrl] + data[:logoImage] = current_publisher.site_banner.read_only_react_property[:logoUrl] + render(json: data.to_json) + end + + def update_logo + if params[:image].length > MAX_IMAGE_SIZE + # (Albert Wang): We should consider supporting alerts. This might require a UI redesign + # alert[:error] = "File size too big!" + head :payload_too_large and return + end + site_banner = current_publisher.site_banner + update_image(attachment: site_banner.logo, attachment_type: SiteBanner::LOGO) + head :ok + end + + def update_background_image + if params[:image].length > MAX_IMAGE_SIZE + # (Albert Wang): We should consider supporting alerts. This might require a UI redesign + # alert[:error] = "File size too big!" + head :payload_too_large and return + end + site_banner = current_publisher.site_banner + update_image(attachment: site_banner.background_image, attachment_type: SiteBanner::BACKGROUND) + head :ok + end + + private + + def update_image(attachment:, attachment_type:) + data_url = params[:image].split(',')[0] + if data_url.starts_with?("data:image/jpeg") + content_type = "image/jpeg" + extension = ".jpg" + elsif data_url.starts_with?("data:image/png") + content_type = "image/png" + extension = ".png" + elsif data_url.starts_with?("data:image/bmp") + content_type = "image/bmp" + extension = ".bmp" + else + LogException.perform(StandardError.new("Unknown image format:" + data_url), params: {}) + return nil + end + filename = Time.now.to_s.gsub!(" ", "_").gsub!(":", "_") + current_publisher.id + + temp_file = Tempfile.new([filename, extension]) + File.open(temp_file.path, 'wb') do |f| + f.write(Base64.decode64(params[:image].split(',')[1])) + end + + original_image_path = temp_file.path + + resized_jpg_path = resize_to_dimensions_and_convert_to_jpg( + source_image_path: original_image_path, + attachment_type: attachment_type, + filename: filename + ) + + begin + padded_resized_jpg_path = add_padding_to_image( + source_image_path: resized_jpg_path, + attachment_type: attachment_type, + ) + rescue OutsidePaddingRangeError + logger.error "Outside padding range" + LogException.perform(StandardError.new("File size too big for #{attachment_type}"), params: {publisher_id: current_publisher.id}) + end + + new_filename = generate_filename(source_image_path: padded_resized_jpg_path) + + attachment.attach( + io: open(padded_resized_jpg_path), + filename: new_filename + ".jpg", + content_type: "image/jpg" + ) + end +end diff --git a/app/controllers/publishers_controller.rb b/app/controllers/publishers_controller.rb index dc5825e68c..719a55cdf0 100644 --- a/app/controllers/publishers_controller.rb +++ b/app/controllers/publishers_controller.rb @@ -199,13 +199,13 @@ def update end respond_to do |format| - format.json { - if success - head :no_content - else - render(json: { errors: publisher.errors }, status: 400) - end - } + if success + format.json { head :no_content } + format.html { redirect_to home_publishers_path } + else + format.json { render(json: { errors: publisher.errors }, status: 400) } + format.html { render(status: 400) } + end end end diff --git a/app/helpers/image_conversion_helper.rb b/app/helpers/image_conversion_helper.rb new file mode 100644 index 0000000000..4970317887 --- /dev/null +++ b/app/helpers/image_conversion_helper.rb @@ -0,0 +1,87 @@ +module ImageConversionHelper + IMAGE_QUALITY = 75 + + def resize_to_dimensions_and_convert_to_jpg(source_image_path:, attachment_type:, filename:) + # Set dimensions + mini_magick_image = MiniMagick::Image.open(source_image_path) + if attachment_type == SiteBanner::LOGO + mini_magick_image.resize(SiteBanner::LOGO_DIMENSIONS.join("x")) + elsif attachment_type == SiteBanner::BACKGROUND + mini_magick_image.resize(SiteBanner::BACKGROUND_DIMENSIONS.join("x")) + else + LogException.perform(StandardError.new("Unknown attachment type:" + attachment_type), params: {}) + return nil + end + + # Use JPG as its the most efficient standard + mini_magick_image.format "jpg" + + new_filename = filename + "_resized" + temp_file = Tempfile.new([new_filename, ".jpg"]) + + mini_magick_image.write(temp_file) + + temp_file.path + end + +=begin + Adding an empty comment adds an arbitrary number of bytes + Add a character to a comment adds 5 bytes (4 for padding) +=end + def add_padding_to_image(source_image_path:, attachment_type:) + # Add initial conversion to get file size + if attachment_type == SiteBanner::LOGO + target_file_size = SiteBanner::LOGO_UNIVERSAL_FILE_SIZE + elsif attachment_type == SiteBanner::BACKGROUND + target_file_size = SiteBanner::BACKGROUND_UNIVERSAL_FILE_SIZE + else + LogException.perform(StandardError.new("Unknown attachment_type:" + attachment_type), params: {}) + end + + file_size_after_one_byte = calculate_image_size_after_pad_one_byte(source_image_path) + + delta = target_file_size - file_size_after_one_byte + + if delta < 0 + raise OutsidePaddingRangeError + end + + MiniMagick::Tool::Convert.new do |convert| + convert << source_image_path + convert.merge!(["-set", "comment", "a" * (delta + 1)]) + convert.merge!(["-quality", IMAGE_QUALITY]) + convert << source_image_path + end + + source_image_path + end + + def generate_filename(source_image_path:) + File.open(source_image_path, 'r') do |f| + Digest::SHA256.hexdigest f.read + end + end + + private + + def calculate_image_size_after_pad_one_byte(source_image_path) + mini_magick_image = MiniMagick::Image.open(source_image_path) + + new_filename = "_resized" + + temp_file = Tempfile.new([new_filename, ".jpg"]) + + mini_magick_image.write(temp_file) + + MiniMagick::Tool::Convert.new do |convert| + convert << temp_file.path + convert.merge!(["-set", "comment", "a"]) + convert.merge!(["-quality", IMAGE_QUALITY]) + convert << temp_file.path + end + + File.size(temp_file.path) + end + + class OutsidePaddingRangeError < RuntimeError; end +end diff --git a/app/javascript/locale/en.js b/app/javascript/locale/en.js new file mode 100644 index 0000000000..0bf7096aee --- /dev/null +++ b/app/javascript/locale/en.js @@ -0,0 +1,10 @@ +const locale = { + about: 'about', + donationAmount: 'Donation amount', + makeMonthly: 'Make this monthly', + sendDonation: 'Send my donation', + tokens: 'tokens', + walletBalance: 'wallet balance', +}; + +export default locale; diff --git a/app/javascript/packs/brave_rewards_banner.jsx b/app/javascript/packs/brave_rewards_banner.jsx new file mode 100644 index 0000000000..da2718ded9 --- /dev/null +++ b/app/javascript/packs/brave_rewards_banner.jsx @@ -0,0 +1,443 @@ +import React from 'react' + +import BatsBackground from '../../assets/images/bg_bats.svg' +import HeartsBackground from '../../assets/images/bg_hearts.svg' +import { BatColorIcon, YoutubeColorIcon, TwitterColorIcon, TwitchColorIcon } from 'brave-ui/components/icons' +import Checkbox from 'brave-ui/components/formControls/checkbox' + +import {styles} from '../packs/brave_rewards_banner.style.jsx' + +export default class BraveRewardsBanner extends React.Component { + constructor(props) { + super(props); + + this.state = { + title: 'Your title', + description: 'Welcome to Brave Rewards banner', + backgroundImage: null, + backgroundImageData: '', + logoImage: null, + logoImageData: '', + youtube: '', + twitter: '', + twitch: '', + conversionRate: 0.2, + donationAmounts: [1, 5, 10], + mode: 'Edit', + width: '1320' + } + this.handleBackgroundImageUpload = this.handleBackgroundImageUpload.bind(this); + this.handleLogoImageUpload = this.handleLogoImageUpload.bind(this); + this.updateTitle = this.updateTitle.bind(this); + this.updateDescription = this.updateDescription.bind(this) + this.handleSave = this.handleSave.bind(this); + this.fetchSiteBanner = this.fetchSiteBanner.bind(this); + this.updateYoutube = this.updateYoutube.bind(this); + this.updateTwitter = this.updateTwitter.bind(this); + this.updateTwitch = this.updateTwitch.bind(this); + this.fetchSiteBanner = this.fetchSiteBanner.bind(this); + this.updateWindowDimensions = this.updateWindowDimensions.bind(this); + } + + componentWillMount(){ + this.modalize(); + } + + componentDidMount(){ + this.fetchSiteBanner(); + document.getElementsByClassName('brave-rewards-banner-control-bar-save-button')[0].addEventListener("click", this.handleSave); + window.addEventListener('resize', this.updateWindowDimensions); + } + + updateWindowDimensions() { + if(window.innerWidth < 991){ + this.close(); + } + else{ + this.setState({ width: 1320}); + } +} + + modalize(){ + document.getElementsByClassName("modal-panel")[0].style.maxWidth = 'none'; + document.getElementsByClassName("modal-panel")[0].style.padding = '0px'; + document.getElementsByClassName("modal-panel--content")[0].style.padding = '0px'; + } + + close(){ + document.getElementsByClassName("modal-panel")[0].style.maxWidth = '40rem'; + document.getElementsByClassName("modal-panel")[0].style.padding = '2rem 2rem'; + document.getElementsByClassName("modal-panel--content")[0].style.padding = '1rem 1rem 0 1rem'; + document.getElementsByClassName("modal-panel--close js-deny")[0].click(); + } + + fetchSiteBanner(){ + let that = this + let id = document.getElementById("publisher_id").value; + let url = '/publishers/' + id + "/site_banners/fetch"; + + fetch(url, { + method: 'GET', + headers: { + 'Accept': 'text/html', + 'X-Requested-With': 'XMLHttpRequest', + 'X-CSRF-Token': document.head.querySelector("[name=csrf-token]").content + }, + credentials: "same-origin", + }).then(function(response) { + return response.json(); + }) + .then(function(banner) { + + that.setState({ + title: banner.title, + description: banner.description, + backgroundImage: banner.backgroundImage, + youtube: banner.social_links.youtube, + twitter: banner.social_links.twitter, + twitch: banner.social_links.twitch, + donationAmounts: banner.donation_amounts, + }) + + that.cropFetchedLogo(banner.logoImage, that); + }); + } + + updateTitle(event){ + this.setState({title: event.target.value}) + } + + updateDescription(event){ + this.setState({description: event.target.value}) + } + + updateYoutube(event){ + this.setState({youtube: event.target.value}) + } + + updateTwitter(event){ + this.setState({twitter: event.target.value}) + } + + updateTwitch(event){ + this.setState({twitch: event.target.value}) + } + + updateDonationAmounts(event, index){ + let temp = this.state.donationAmounts + if(/^(\s*|\d+)$/.test(event.target.value)){ + temp[index] = event.target.value + this.setState({donationAmounts: temp}) + } + } + + handleBackgroundImageUpload(event) { + if (!event.target.files[0]) { + return + } + this.setState({backgroundImage: URL.createObjectURL(event.target.files[0]), backgroundImageData: event.target}) + } + + handleLogoImageUpload(event) { + let that = this; + this.cropLogo(event, that); + } + + cropFetchedLogo(logo, that){ + let img = new Image(); + img.src = logo; + img.onload = function() { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + canvas.width = 160; + canvas.height = 160; + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + let url = canvas.toDataURL('image/jpeg', 1); + that.setState({logoImage: url}); + } + } + + cropLogo(event, that){ + if (event.target.files && event.target.files[0]) { + var filerdr = new FileReader(); + + filerdr.onload = function(e) { + var img160 = new Image(); + var img480 = new Image(); + + img480.onload = function() { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + canvas.width = 480; + canvas.height = 480; + ctx.drawImage(img480, 0, 0, canvas.width, canvas.height); + canvas.toBlob(function(blob){ + let file = {}; + file["files"] = [blob] + that.setState({logoImageData: file}); + }); + } + + img160.onload = function() { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + canvas.width = 160; + canvas.height = 160; + ctx.drawImage(img160, 0, 0, canvas.width, canvas.height); + let url = canvas.toDataURL('image/jpeg', 1); + that.setState({logoImage: url}); + } + + img160.src = e.target.result; + img480.src = e.target.result; + } + filerdr.readAsDataURL(event.target.files[0]); + } + } + + handleSave(event) { + let that = this + let id = document.getElementById("publisher_id").value; + let url = '/publishers/' + id + "/site_banners"; + let body = new FormData(); + + body.append('title', this.state.title); + body.append('description', this.state.description); + body.append('donation_amounts', JSON.stringify(this.state.donationAmounts)); + body.append('social_links', JSON.stringify({youtube: this.state.youtube, twitter: this.state.twitter, twitch: this.state.twitch})); + + fetch(url, { + method: 'POST', + headers: { + 'Accept': 'text/html', + 'X-Requested-With': 'XMLHttpRequest', + 'X-CSRF-Token': document.head.querySelector("[name=csrf-token]").content + }, + credentials: "same-origin", + body: body + }).then ( + function(response) { + function submitById(id, suffix) { + + const url = '/publishers/' + document.getElementById("publisher_id").value + "/site_banners/update_" + suffix; + + let file; + if(suffix === 'background_image'){ file = that.state.backgroundImageData } + else if(suffix === 'logo'){ file = that.state.logoImageData } + + if (file === "" || file === null) { return; } + var reader = new FileReader(); + reader.readAsDataURL(file.files[0]); + + reader.onloadend = function () { + const body = new FormData(); + body.append('image', reader.result); + fetch(url, { + method: 'POST', + headers: { + 'Accept': 'text/html', + 'X-Requested-With': 'XMLHttpRequest', + 'X-CSRF-Token': document.head.querySelector("[name=csrf-token]").content + }, + credentials: "same-origin", + body: body + }); + } + } + + if (response.status === 200) { + submitById("background-image-select-input", "background_image"); + submitById("logo-image-select-input", "logo"); + } + }).then( + function(response) { + that.close(); + }); + } + + render() { + + let style = styles + + let logoImg + let logoLabel + let backgroundImageLabel + let backgroundImg + let donationsInput + let explanatoryTitle + let explanatoryDescription + let socialLinkText + + let rewardsBanner = { + maxWidth: this.state.width, + height:'488px', + overflow:'hidden' + } + + + + if(this.props.mode === 'Edit'){ + logoLabel = { height:'100%', width:'100%', borderRadius: '50%', border: '2px dotted white', cursor:'pointer'} + backgroundImageLabel = {height:'100%', width:'100%', border: '2px dotted white', cursor:'pointer'} + + explanatoryTitle = {width:'100%', height:'50px', backgroundColor: 'rgba(0, 0, 0, 0)', border: '1px solid lightGray', borderRadius: '4px', marginTop: '15px', fontSize: '32px', color: '#686978'} + explanatoryDescription = {width:'100%', height:'150px', resize: 'none', backgroundColor: 'rgba(0, 0, 0, 0)', border:'1px solid lightGray', borderRadius: '4px', marginTop: '25px', fontSize: '22px', color: '#686978'} + donationsInput = {backgroundColor: 'rgba(0, 0, 0, 0)', marginRight:'5px', border: '1px solid lightGray', borderRadius: '4px', color: 'white', height:'19px'} + socialLinkText = {marginTop:'auto', marginBottom:'auto', borderBottom: '1px solid lightGray', borderTop: '1px solid rgba(0, 0, 0, 0)', borderLeft: '1px solid rgba(0, 0, 0, 0)', color: '#686978', width: '90px', fontSize: '15px', backgroundColor: 'rgba(0, 0, 0, 0)', borderRadius: '0px'} + + if(this.state.backgroundImage === null){ + backgroundImg = {height: '176px', padding: '10px', background: `url(${BatsBackground}) left top no-repeat, url(${HeartsBackground}) right top no-repeat, rgb(158, 159, 171)`} + } + else{ + backgroundImg = {height: '176px', padding: '10px', background: `linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(${this.state.backgroundImage})`} + } + if(this.state.logoImage === null){ + logoImg = {position: 'absolute', top: '190px', left: '35px', borderRadius: '50%', width: '160px', height: '160px', border: '6px solid white', padding: '10px', backgroundColor:'#FB542B'} + } + else{ + logoImg = {position: 'absolute', top: '190px', left: '35px', borderRadius: '50%', width: '160px', height: '160px', border: '6px solid white', padding: '10px', background:`url(${this.state.logoImage})`} + } + } + else{ + logoLabel = { height:'100%', width:'100%', borderRadius: '50%', border: 'none', pointerEvents: 'none'} + backgroundImageLabel = {height:'100%', width:'100%', border: 'none', pointerEvents: 'none'} + + explanatoryTitle = {width:'100%', height:'50px', backgroundColor: 'rgba(0, 0, 0, 0)', border: '1px solid rgba(0, 0, 0, 0)', borderRadius: '4px', marginTop: '15px', fontSize: '32px', color: '#686978', userSelect:'none'} + explanatoryDescription = {width:'100%', height:'150px', resize: 'none', backgroundColor: 'rgba(0, 0, 0, 0)', border:'1px solid rgba(0, 0, 0, 0)', borderRadius: '4px', marginTop: '25px', fontSize: '22px', color: '#686978', userSelect:'none'} + donationsInput = {backgroundColor: 'rgba(0, 0, 0, 0)', marginRight:'5px', border: '1px solid rgba(0, 0, 0, 0)', borderRadius: '4px', color: 'white'} + socialLinkText = {marginTop:'auto', marginBottom:'auto', borderBottom: '1px solid rgba(0, 0, 0, 0)', borderTop: '1px solid rgba(0, 0, 0, 0)', borderLeft: '1px solid rgba(0, 0, 0, 0)', color: '#686978', width: '90px', fontSize: '15px', backgroundColor: 'rgba(0, 0, 0, 0)', borderRadius: '0px', userSelect: 'none'} + + if(this.state.backgroundImage === null){ + backgroundImg = {height: '176px', padding: '10px', background: `url(${BatsBackground}) left top no-repeat, url(${HeartsBackground}) right top no-repeat, rgb(158, 159, 171)`} + } + else{ + backgroundImg = {height: '176px', padding: '10px', background: `url(${this.state.backgroundImage})`} + } + if(this.state.logoImage === null){ + logoImg = {position: 'absolute', top: '190px', left: '35px', borderRadius: '50%', width: '160px', height: '160px', border: '6px solid white', padding: '10px', backgroundColor:'#FB542B'} + } + else{ + logoImg = {position: 'absolute', top: '190px', left: '35px', borderRadius: '50%', width: '160px', height: '160px', border: '6px solid white', padding: '10px', background:`url(${this.state.logoImage})`} + } + } + + style.logoLabel = logoLabel + style.backgroundImageLabel = backgroundImageLabel + style.logoImg = logoImg + style.backgroundImg = backgroundImg + style.explanatoryTitle = explanatoryTitle + style.explanatoryDescription = explanatoryDescription + style.donationsInput = donationsInput + style.socialLinkText = socialLinkText + style.rewardsBanner = rewardsBanner + + return ( +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +