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 c806f170dc..4caa477515 100644
--- a/Gemfile
+++ b/Gemfile
@@ -16,6 +16,9 @@ gem "api-pagination"
# Encrypt DB data at rest
gem "attr_encrypted", "~> 3.1.0"
+# Use AWS gem for s3 uploads
+gem 'aws-sdk-s3', require: false
+
gem "bootstrap", "~> 4.1.1"
# browser details
diff --git a/Gemfile.lock b/Gemfile.lock
index ff2f8c0179..76799cc314 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -68,6 +68,21 @@ GEM
encryptor (~> 3.0.0)
autoprefixer-rails (9.0.0)
execjs
+ aws-eventstream (1.0.1)
+ aws-partitions (1.98.0)
+ aws-sdk-core (3.24.1)
+ aws-eventstream (~> 1.0)
+ aws-partitions (~> 1.0)
+ aws-sigv4 (~> 1.0)
+ jmespath (~> 1.0)
+ aws-sdk-kms (1.7.0)
+ aws-sdk-core (~> 3)
+ aws-sigv4 (~> 1.0)
+ aws-sdk-s3 (1.17.0)
+ aws-sdk-core (~> 3, >= 3.21.2)
+ 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)
@@ -158,6 +173,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)
@@ -435,6 +451,7 @@ DEPENDENCIES
activerecord-session_store
api-pagination
attr_encrypted (~> 3.1.0)
+ aws-sdk-s3
bootstrap (~> 4.1.1)
brakeman
browser
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 @@
+
+
\ No newline at end of file
diff --git a/app/assets/stylesheets/pages/home.scss b/app/assets/stylesheets/pages/home.scss
index 7594ed853b..edc0ad5fa3 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..55db323522
--- /dev/null
+++ b/app/controllers/publishers/site_banners_controller.rb
@@ -0,0 +1,56 @@
+class Publishers::SiteBannersController < ApplicationController
+ 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[1],
+ social_links: params[:social_links],
+ description: params[:description]
+ )
+ head :ok
+ end
+
+ def update_logo
+ site_banner = current_publisher.site_banner
+ update_image(site_banner.logo)
+ head :ok
+ end
+
+ def update_background_image
+ site_banner = current_publisher.site_banner
+ update_image(site_banner.background_image)
+ head :ok
+ end
+
+ private
+
+ def update_image(attachment)
+ 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"
+ else
+ # TODO: Throw an exception here
+ end
+ filename = Time.now.to_s.gsub!(" ", "_").gsub!(":", "_") + current_publisher.id + "_logo"
+
+ file = Tempfile.new([filename, extension])
+ File.open(file.path, 'wb') do |f|
+ f.write(Base64.decode64(params[:image].split(',')[1]))
+ end
+ attachment.attach(io: open(file.path),
+ filename: filename,
+ content_type: content_type
+ )
+ end
+end
diff --git a/app/javascript/locale/en.js b/app/javascript/locale/en.js
new file mode 100644
index 0000000000..4f5e6d77cc
--- /dev/null
+++ b/app/javascript/locale/en.js
@@ -0,0 +1,86 @@
+const locale = {
+ about: 'about',
+ addFunds: 'add funds',
+ allowTip: 'Allow tips on',
+ braveRewards: 'Brave Rewards',
+ cancel: 'Cancel',
+ claim: 'Claim',
+ copy: 'Copy',
+ currentDonation: 'You’re currently donating {{currentDonation}} BAT to this site every month.',
+ detail: 'Detail',
+ donationAmount: 'Donation amount',
+ done: 'Done',
+ earningsAds: 'Earnings from Brave Ads',
+ expiresOn: 'expires on',
+ import: 'import',
+ makeMonthly: 'Make this monthly',
+ monthApr: 'Apr',
+ monthAug: 'August',
+ monthDec: 'December',
+ monthFeb: 'February',
+ monthJan: 'January',
+ monthJul: 'July',
+ monthJun: 'June',
+ monthMar: 'March',
+ monthMay: 'May',
+ monthNov: 'November',
+ monthOct: 'October',
+ monthSep: 'September',
+ noGrants: 'Currently no token grant is available.',
+ notEnoughTokens: 'Not enough tokens. Please',
+ on: 'on',
+ oneTime: 'One time',
+ oneTimeDonation: 'One-time Donations/Tips',
+ print: 'Print',
+ recoveryKeys: 'Recovery Key',
+ recurring: 'Recurring',
+ recurringDonations: 'Recurring Donations',
+ remove: 'remove',
+ restore: 'Restore',
+ rewardsBackupText1: 'Backup your Wallet',
+ rewardsBackupText2: 'Keep this anonymized recovery key for your Brave wallet in the safe place in case you lose access to this browser. Your funds are safe as long as you keep this recovery key either on a paper or in a device with preferably no internet connection.',
+ rewardsBannerText1: 'Thanks for stopping by. We joined Brave’s vision of protecting your privacy because we believe that fans like you would support us in our effort to keep the web a clean and safe place to be.',
+ rewardsBannerText2: 'Your donation is much appreciated and it encourages us to continue to improve our content.',
+ rewardsContribute: 'Brave Contribute',
+ rewardsContributeAttention: 'Your attention metric',
+ rewardsContributeText1: 'You’re currently supporting',
+ rewardsContributeVisited: 'Site visited',
+ rewardsOffText1: 'Do you know that you’ve been paying for the web content with your data for the digital ads? You didn’t have a voice in it and worse, you’re exposed to privacy and security risks.',
+ rewardsOffText2: 'Brave Rewards allows you to take control back.',
+ rewardsOffText3: 'How does it work?',
+ rewardsOffText4: 'Your attention is valuable. Get paid for the ads. And pay directly the favorite content creators at your will. That way, they can grow and continue delivering the content that delights you.',
+ rewardsPanelEmptyText1: 'Sadly, no tokens yet.',
+ rewardsPanelEmptyText2: '3 ways to fill your wallet:',
+ rewardsPanelEmptyText3: 'You can add funds.',
+ rewardsPanelEmptyText4: 'You can earn tokens from Brave Ads.',
+ rewardsPanelEmptyText5: 'Occasionally, you will also received token grants from Brave. So keep an eye out for the alert!',
+ rewardsPanelOffText1: 'Get Rewarded for Browsing!',
+ rewardsPanelOffText2: 'Earn tokens for your attention to ads and pay it forward to support content creators you value!',
+ rewardsPanelText1: 'Add, withdraw and manage funds at',
+ rewardsPanelText2: 'Brave wallet is managed by',
+ rewardsRestoreText1: 'Restore your Wallet',
+ rewardsRestoreText2: 'Enter the recovery key to restore your Brave wallet. Make sure that the current wallet doesn’t have any balance or is backed up safely. Restoring a wallet replaces the current wallet and you will loose any balance if you don’t back up its recovery key.',
+ rewardsRestoreText3: 'Enter your recovery key or',
+ rewardsSummary: 'Rewards Summary',
+ rewardsWhy: 'Why Brave Rewards…',
+ saveAsFile: 'Save as File',
+ seeAllItems: 'See all {{numItems}} items',
+ seeAllSites: 'See all {{numSites}} sites',
+ sendDonation: 'Send my donation',
+ sendTip: 'Send my Tip',
+ settings: 'Settings',
+ siteVisited: 'Site visited',
+ sites: 'sites',
+ tipOnLike: 'Tip on like',
+ tokenBalance: 'Token balance',
+ tokenGrant: 'Token Grant',
+ tokens: 'tokens',
+ type: 'Type',
+ verifiedPublisher: 'Brave Verified Publisher',
+ walletActivity: 'Wallet Activity/ Monthly Statement',
+ walletBalance: 'wallet balance',
+ welcome: 'Welcome!',
+ yourWallet: 'Your wallet'
+};
+
+export default locale;
diff --git a/app/javascript/packs/brave_rewards_banner_display.jsx b/app/javascript/packs/brave_rewards_banner_display.jsx
new file mode 100644
index 0000000000..4a096af3d3
--- /dev/null
+++ b/app/javascript/packs/brave_rewards_banner_display.jsx
@@ -0,0 +1,480 @@
+// Run this example by adding <%= javascript_pack_tag 'hello_react' %> to the head of your layout file,
+// like app/views/layouts/application.html.erb. All it does is render
ButtonPrimary
at the bottom
+// of the page.
+
+import React from 'react'
+import ReactDOM from 'react-dom'
+import PropTypes from 'prop-types'
+import SiteBanner from 'brave-ui/features/rewards/siteBanner'
+import { initLocale } from 'brave-ui'
+import locale from 'locale/en'
+
+class BraveRewardsPageForm extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ title: props.details.title || 'YOUR TITLE',
+ description: props.details.description || 'A brief description',
+ backgroundImage: props.details.backgroundUrl,
+ logo: props.details.logoUrl,
+ donationAmounts: props.details.donationAmounts || [1, 5, 10],
+ socialLinks: props.details.socialLinks || {'twitter': '@', 'youtube': '@', 'twitch': '@'},
+ };
+
+ this.updateDescription = this.updateDescription.bind(this);
+ this.updateTwitch = this.updateTwitch.bind(this);
+ this.updateYoutube = this.updateYoutube.bind(this);
+ this.updateTwitter = this.updateTwitter.bind(this);
+ this.handleLogoImageChange = this.handleLogoImageChange.bind(this);
+ this.handleBackgroundImageChange = this.handleBackgroundImageChange.bind(this);
+ this.handleDonationAmountsChange = this.handleDonationAmountsChange.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ }
+
+ isNormalInteger(str) {
+ return /^\+?(0|[1-9]\d*)$/.test(str);
+ }
+
+ convertDonationAmounts(donationAmounts) {
+ if (donationAmounts == null) return null;
+
+ return donationAmounts.map(
+ amount => ({
+ 'tokens': amount,
+ 'converted': this.props.conversionRate * amount,
+ 'selected': false
+ })
+ );
+ }
+
+ handleDonationAmountsChange(event) {
+ this.setState({
+ donationAmounts:
+ document.getElementById("donation-amounts-input").value.split(',').map(Number)
+ });
+ }
+
+ handleLogoImageChange(event) {
+ this.setState({logo: URL.createObjectURL(event.target.files[0])});
+ var logoImageDiv = document.getElementsByClassName("brave-rewards-banner--logo-no-attachment")[0];
+ var logoDiv = document.getElementsByClassName("sc-dnqmqq")[0];
+
+ if (this.state.logo != null) {
+ logoImageDiv.classList.remove("brave-rewards-banner--logo-no-attachment");
+ logoImageDiv.classList.add("brave-rewards-banner--logo-camera");
+ logoDiv.classList.add("brave-rewards-banner--logo-parent");
+ }
+ }
+
+ applyFade() {
+ if(this.props.editMode){
+ let bgClass = document.getElementsByClassName('sc-EHOje')[0].classList[1];
+ let bgElement = document.getElementsByClassName('sc-EHOje ' + bgClass)[0];
+ let bgStyle = getComputedStyle(bgElement);
+ let bgUrl = bgStyle.background.match(/url\(([^)]+)\)/i)[1];
+ let bgFaded = 'linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(' + bgUrl + ')';
+
+ //Check for default image
+ if(!bgUrl.includes('/rewards/siteBanner/assets/')){
+ bgElement.style.backgroundImage = bgFaded
+ }
+ }
+ }
+
+ handleBackgroundImageChange(event) {
+ this.setState({backgroundImage: URL.createObjectURL(event.target.files[0])});
+ this.applyFade();
+ }
+
+ setupBackgroundLabel() {
+ // Allow uploads
+ var backgroundButton = document.createElement("button");
+ backgroundButton.id = "background-image-select-button";
+ backgroundButton.classList.add("camera-background");
+
+ var backgroundInput = document.createElement("input");
+ backgroundInput.id="background-image-select-input";
+ backgroundInput.type="file";
+ backgroundInput.style.display = "none";
+ backgroundInput.onchange = this.handleBackgroundImageChange;
+
+ backgroundButton.addEventListener("click", function (e) {
+ if (backgroundInput) {
+ backgroundInput.click();
+ }
+ }, false);
+
+ var label = document.createElement("label");
+ label.innerHTML="900 x 176";
+ label.classList.add("brave-rewards-banner--background-label");
+
+ var backgroundDiv = document.getElementsByClassName("sc-EHOje")[0];
+ var callToActionDiv = document.createElement("div");
+ callToActionDiv.classList.add("brave-rewards-banner--background-camera");
+ backgroundDiv.append(callToActionDiv);
+ callToActionDiv.appendChild(backgroundInput);
+ callToActionDiv.appendChild(backgroundButton);
+ callToActionDiv.appendChild(label);
+ }
+
+ setupLogoLabel() {
+ // Allow uploads
+ var logoButton = document.createElement("button");
+ logoButton.id = "logo-image-select-button";
+ logoButton.classList.add("camera-background");
+
+ var logoInput = document.createElement("input");
+ logoInput.id="logo-image-select-input";
+ logoInput.type="file";
+ logoInput.style.display = "none";
+ logoInput.onchange = this.handleLogoImageChange;
+
+ logoButton.addEventListener("click", function (e) {
+ if (logoInput) {
+ logoInput.click();
+ }
+ }, false);
+
+ var label = document.createElement("label");
+ label.innerHTML="148 x 148";
+ label.classList.add("brave-rewards-banner--logo-label");
+
+ var logoDiv = document.getElementsByClassName("sc-dnqmqq")[0];
+ logoDiv.classList.add("brave-rewards-banner--logo-parent");
+ var callToActionDiv = document.createElement("div");
+ if (this.state.logo == null) {
+ callToActionDiv.classList.add("brave-rewards-banner--logo-no-attachment");
+ } else {
+ callToActionDiv.classList.add("brave-rewards-banner--logo-camera");
+ }
+ logoDiv.prepend(callToActionDiv);
+ callToActionDiv.appendChild(logoInput);
+ callToActionDiv.appendChild(logoButton);
+ callToActionDiv.appendChild(label);
+ }
+
+ componentDidMount() {
+
+ this.applyFade();
+
+ if (this.props.editMode) {
+ this.setupBackgroundLabel();
+ this.setupLogoLabel();
+
+ // Set h3 editable
+ document.getElementsByClassName("sc-gZMcBi")[0].setAttribute("contenteditable", true)
+
+ // Set p editable
+ // document.getElementsByClassName("sc-gqjmRU")[0].setAttribute("contenteditable", true)
+
+ var hiddenDonationAmounts = document.createElement('input');
+ hiddenDonationAmounts.id = 'donation-amounts-input';
+ hiddenDonationAmounts.type = "hidden"
+ hiddenDonationAmounts.style.display = 'none';
+ hiddenDonationAmounts.onchange = this.handleDonationAmountsChange;
+ document.body.appendChild(hiddenDonationAmounts);
+
+ // Editable for tokens
+ for (let element of document.getElementsByClassName("sc-brqgnP")) {
+ element.setAttribute("contenteditable", true);
+ var observer = new MutationObserver(function(mutations) {
+ mutations.forEach(function(mutation) {
+ if (mutation.type == "contentList") {
+ return;
+ }
+ // TODO: (Albert Wang) Make sure the input are valid numbers
+ var donationAmounts = [];
+ for (let amountSpan of document.getElementsByClassName("sc-brqgnP")) {
+ donationAmounts.push(parseInt(amountSpan.textContent));
+ }
+ document.getElementById("donation-amounts-input").value = donationAmounts;
+ document.getElementById("donation-amounts-input").onchange();
+ });
+ });
+ // configuration of the observer:
+ var config = { characterData: true, attributes: false, childList: true, subtree: true };
+ // pass in the target node, as well as the observer options
+ observer.observe(element, config);
+ };
+
+ // Hide X-mark
+ document.getElementsByClassName("sc-bZQynM")[0].style = "display: none";
+ }
+ }
+
+ submitById(id, suffix) {
+ const url = '/publishers/' + this.props.publisher_id + "/site_banners/update_" + suffix;
+ var file = document.getElementById(id);
+ var reader = new FileReader();
+
+ // Don't upload if user didn't upload a new image
+ if (file.value == "" || file.value == null) {
+ return;
+ }
+ 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
+ });
+ };
+ }
+
+ updateDescription(event) {
+ this.setState({description: event.target.value})
+ }
+
+ updateTwitch(event) {
+ let temp = this.state.socialLinks
+ temp.twitch = event.target.value
+ this.setState({socialLink : temp});
+ }
+
+ updateYoutube(event) {
+ let temp = this.state.socialLinks
+ temp.youtube = event.target.value
+ this.setState({socialLink : temp});
+ }
+
+ updateTwitter(event) {
+ let temp = this.state.socialLinks
+ temp.twitter = event.target.value
+ this.setState({socialLink : temp});
+ }
+
+ /*
+ setTextsFromDiv() {
+ this.setState({
+ title: document.getElementsByClassName("sc-gZMcBi")[0].innerText,
+ description: document.getElementsByClassName("sc-gqjmRU")[0].innerText
+ });
+ }
+ */
+
+ handleSubmit(event) {
+ const url = '/publishers/' + this.props.publisher_id + "/site_banners";
+ var request = new XMLHttpRequest();
+ const body = new FormData();
+
+ body.append('title', document.getElementsByClassName("sc-gZMcBi")[0].innerText);
+ body.append('description', this.state.description);
+ body.append('donation_amounts', JSON.stringify(this.state.donationAmounts));
+ body.append('social_links', JSON.stringify(this.state.socialLinks));
+
+ 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;
+ var file = document.getElementById(id);
+ var reader = new FileReader();
+
+ // Don't upload if user didn't upload a new image
+ if (file.value == "" || file.value == null) {
+ return;
+ }
+ 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");
+ }
+ // TODO: (Albert Wang): Make sure the above code doesn't reach here until a response is received
+ }).then(
+ function(response) {
+ ReactDOM.unmountComponentAtNode(document.getElementsByClassName("modal-panel--content")[0]);
+ document.getElementsByClassName("modal-panel--close")[0].click();
+ });
+ }
+
+ render() {
+ initLocale(locale);
+
+ let topController;
+
+ if (this.props.editMode) {
+ topController =
+
+ Don't Change
+ Preview Banner
+ Save Change
+
+ } else {
+ topController = Close
+ }
+
+ return (
+
+
+
+
+
+
+ {
+ // this.state.socialLinks.twitter !== undefined &&
+
+ }
+ {
+ // this.state.socialLinks.youtube !== undefined &&
+
+ }
+ {
+ // this.state.socialLinks.twitch !== undefined &&
+
+ }
+
+
+
+
+
+
+
+ );
+ }
+}
+
+/*
+
+ */
+
+export function renderBraveRewardsBannerDisplay(editMode) {
+ const braveRewardsPageForm = ;
+
+ ReactDOM.render(
+ braveRewardsPageForm,
+ document.getElementById("instant-donation-modal").parentElement.parentElement
+ )
+ document.getElementById('site_banner').children[1].style.height = '0vh';
+
+ // Resize modal container
+ document.getElementsByClassName("modal-container")[0].style.height = document.getElementById('site_banner').children[1].children[0].offsetHeight + "px";
+ document.getElementsByClassName("modal-container")[0].style.width = document.getElementById('site_banner').children[1].children[0].offsetWidth + "px";
+
+ // Reset margins
+ document.getElementsByClassName("modal-panel")[0].style.marginLeft = "0px";
+ document.getElementById("controller-form").style.marginLeft = "-48px";
+ document.getElementById("controller-form").style.marginTop = "-128px";
+ document.getElementById("controller-form").style.paddingTop = "16px";
+ document.getElementById("controller-form").style.width = document.getElementById('site_banner').children[1].children[0].offsetWidth + "px";
+ document.getElementById("controller-form").style.backgroundColor = "white";
+
+ // Hide unused close button
+ document.getElementsByClassName("modal-panel--close")[0].style.visibility = 'hidden';
+
+ /*
+ if (editMode) {
+ // Set h3 editable
+ document.getElementsByClassName("sc-gZMcBi")[0].setAttribute("contenteditable", true)
+
+ // Set p editable
+ document.getElementsByClassName("sc-gqjmRU")[0].setAttribute("contenteditable", true)
+
+ // Editable for tokens
+ for (let element of document.getElementsByClassName("sc-brqgnP")) {
+ element.setAttribute("contenteditable", true)
+ };
+ }
+ */
+
+ document.getElementById("instant-donation-dont-save-changes").onclick = function() {
+ ReactDOM.unmountComponentAtNode(document.getElementsByClassName("modal-panel--content")[0]);
+ document.getElementsByClassName("modal-panel--close")[0].click();
+ }
+}
+
+/*
+ const braveRewardsPageForm = ;
+
+ ReactDOM.render(
+ braveRewardsPageForm,
+ document.body.appendChild(document.createElement("div"))
+ )
+
+ document.getElementById('site_banner').children[0].style.height = '50vh';
+*/
diff --git a/app/javascript/publishers/home.js b/app/javascript/publishers/home.js
index f7af6b2af1..f9f2f6dbe3 100644
--- a/app/javascript/publishers/home.js
+++ b/app/javascript/publishers/home.js
@@ -6,6 +6,7 @@ import fetch from '../utils/fetchPolyfill';
import flash from '../utils/flash';
import { Wallet } from '../wallet';
import { formatFullDate } from '../utils/dates';
+import { renderBraveRewardsBannerDisplay } from '../packs/brave_rewards_banner_display';
// ToDo - import resource strings
const NO_CURRENCY_SELECTED = 'None selected';
@@ -381,6 +382,8 @@ document.addEventListener('DOMContentLoaded', function() {
}
})
+ let instantDonationButton = document.getElementById("instant-donation-button");
+
editContact.addEventListener('click', function(event) {
updateContactName.value = showContactName.innerText;
updateContactEmail.value = pendingContactEmail.innerText || showContactEmail.innerText;
@@ -399,6 +402,19 @@ document.addEventListener('DOMContentLoaded', function() {
event.preventDefault();
}, false);
+ instantDonationButton.addEventListener("click", function(event) {
+ document.getElementById("preview-banner-button").onclick = function() {
+ document.getElementById("instant-donation-modal-selection").style.display = 'none';
+ document.getElementById("instant-donation-modal-preview").style.display = 'block';
+ renderBraveRewardsBannerDisplay(false);
+ };
+ document.getElementById("edit-banner-button").onclick = function() {
+ document.getElementById("instant-donation-modal-selection").style.display = 'none';
+ document.getElementById("instant-donation-modal-edit").style.display = 'block';
+ renderBraveRewardsBannerDisplay(true);
+ };
+ }, false);
+
updateContactForm.addEventListener('submit', function(event) {
event.preventDefault();
submitForm('update_contact', 'PATCH', true)
diff --git a/app/models/json_builders/channels_json_builder.rb b/app/models/json_builders/channels_json_builder.rb
index b8f2e2759e..c379b83988 100644
--- a/app/models/json_builders/channels_json_builder.rb
+++ b/app/models/json_builders/channels_json_builder.rb
@@ -1,5 +1,5 @@
# Builds a list of distinct channels that are either verified, excluded or both for the Brave Browser.
-#
+#
# Each channel is an array:
# [channel_identifier, verified, excluded]
#
@@ -21,10 +21,7 @@ def initialize
def build
channels = []
- [ Channel.verified.site_channels,
- Channel.youtube_channels,
- Channel.twitch_channels,
- Channel.twitter_channels].each do |verified_channels|
+ [Channel.left_joins(publisher: :site_banner).verified.site_channels, Channel.left_joins(publisher: :site_banner).youtube_channels, Channel.left_joins(publisher: :site_banner).twitch_channels, Channel.left_joins(publisher: :site_banner).twitter_channels].each do |verified_channels|
verified_channels.find_each do |verified_channel|
if @excluded_channel_ids.include?(verified_channel.details.channel_identifier)
excluded = true
@@ -32,15 +29,15 @@ def build
else
excluded = false
end
- channels.push([verified_channel.details.channel_identifier, true, excluded])
+ channels.push([verified_channel.details.channel_identifier, true, excluded, verified_channel.publisher&.site_banner&.read_only_react_property || {}])
end
end
@excluded_channel_ids.each do |excluded_channel_id|
next if @excluded_verified_channel_ids.include?(excluded_channel_id)
- channels.push([excluded_channel_id, false, true])
+ channels.push([excluded_channel_id, false, true, {}])
end
channels.to_json
end
-end
\ No newline at end of file
+end
diff --git a/app/models/publisher.rb b/app/models/publisher.rb
index 9643f8090f..38fc1df06a 100644
--- a/app/models/publisher.rb
+++ b/app/models/publisher.rb
@@ -18,6 +18,7 @@ class Publisher < ApplicationRecord
has_many :login_activities
has_many :channels, validate: true, autosave: true
+ has_one :site_banner
has_many :site_channel_details, through: :channels, source: :details, source_type: 'SiteChannelDetails'
has_many :youtube_channel_details, through: :channels, source: :details, source_type: 'YoutubeChannelDetails'
has_many :status_updates, -> { order(created_at: :desc) }, class_name: 'PublisherStatusUpdate'
@@ -272,6 +273,11 @@ def can_create_uphold_cards?
!excluded_from_payout
end
+ # (Albert Wang) We can remove this when beta is done
+ def in_brave_rewards_whitelist?
+ self.email.in?((Rails.application.secrets[:brave_rewards_email_whitelist] || "").split(","))
+ end
+
private
def set_created_status
diff --git a/app/models/site_banner.rb b/app/models/site_banner.rb
new file mode 100644
index 0000000000..cf3899a179
--- /dev/null
+++ b/app/models/site_banner.rb
@@ -0,0 +1,38 @@
+require 'rubygems'
+require 'json'
+
+class SiteBanner < ApplicationRecord
+ include Rails.application.routes.url_helpers
+ has_one_attached :logo
+ has_one_attached :background_image
+ belongs_to :publisher
+
+ def read_only_react_property
+ {
+ title: self.title,
+ description: self.description,
+ backgroundUrl: url_for(self.background_image),
+ logoUrl: url_for(self.logo),
+ donationAmounts: self.donation_amounts,
+ socialLinks: JSON.parse(self.social_links)
+ }
+ end
+
+ def url_for(object)
+ return nil if object.nil? || object.attachment.nil?
+
+ extension = if object.blob.content_type == "image/png"
+ ".png"
+ elsif object.blob.content_type.in?(['image/jpg', 'image/jpeg'])
+ ".jpeg"
+ end
+
+ if Rails.env.development? || Rails.env.test?
+ "https://0.0.0.0:3000" + rails_blob_path(object, only_path: true) + extension
+ elsif Rails.env.staging?
+ return "https://rewards-stg.s3.us-east-2.amazonaws.com/#{object.blob.key}"
+ elsif Rails.env.production?
+ # TODO
+ end
+ end
+end
diff --git a/app/views/application/_nav.html.slim b/app/views/application/_nav.html.slim
index 9bdd0ae53e..216f611c4c 100644
--- a/app/views/application/_nav.html.slim
+++ b/app/views/application/_nav.html.slim
@@ -1,6 +1,10 @@
nav.navbar.navbar-default.navbar-static-top.top-nav-collapse
.container-fluid
.menu-container
+ .nav.pull-left.float-left
+ = link_to(root_path) do
+ .brave-logo
+ = render "logo_wordmark_svg"
.nav.pull-right.float-right
= yield(:navbar_content_right)
- if current_publisher
@@ -32,9 +36,3 @@ nav.navbar.navbar-default.navbar-static-top.top-nav-collapse
log_out_publishers_path, \
class: 'btn btn-secondary btn-highlight btn-outline-primary user-solo-button' \
)
- .nav.pull-left.float-left
- = link_to(root_path) do
- .brave-logo
- = render "logo_wordmark_svg"
- .text-center
- = yield(:navbar_content)
diff --git a/app/views/publishers/_instant_donation_button.html.slim b/app/views/publishers/_instant_donation_button.html.slim
new file mode 100644
index 0000000000..23d83f9f27
--- /dev/null
+++ b/app/views/publishers/_instant_donation_button.html.slim
@@ -0,0 +1 @@
+= link_to("+ #{t "shared.instant_donation"}", "#", data: { "js-confirm-with-modal": "instant-donation-selection" }, class: 'btn btn-secondary btn-highlight', id: 'instant-donation-button')
diff --git a/app/views/publishers/_instant_donation_modal.html.slim b/app/views/publishers/_instant_donation_modal.html.slim
new file mode 100644
index 0000000000..a449bf18b8
--- /dev/null
+++ b/app/views/publishers/_instant_donation_modal.html.slim
@@ -0,0 +1,24 @@
+.col.col-center.col-xs-12.col-sm-12.col-md-12.col-lg-12
+ .modal id="instant-donation-modal" role="dialog" tabindex="-1"
+ .modal-dialog
+ .modal-content
+ .modal-header id="instant-donation-modal-selection"
+ center
+ = image_tag "icn-donation-jar@1x.png", id: 'icn-donation-jar'
+ h4.modal-title = t "shared.instant_donation"
+ p = t "shared.instant_donation_body"
+ .col.col-md-12
+ .row
+ .col-md-3
+ a href="#" class="btn btn-link-primary js-deny" Skip for now
+ .col-md-4
+ = link_to("Preview Banner", "#", class: 'btn btn-primary', id: "preview-banner-button")
+ .col-md-4
+ = link_to("Customize", "#", class: 'btn btn-primary', id: "edit-banner-button")
+ /= link_to "Edit Banner", new_publisher_site_banner_path(current_publisher.id), class: 'btn btn-primary'
+ .modal-header style="display: none;" id="instant-donation-modal-preview"
+ center
+ h4 TODO PREVIEW
+ .modal-header style="display: none;" id="instant-donation-modal-edit"
+ = hidden_field_tag 'publisher_id', current_publisher.id
+ = javascript_pack_tag("brave_rewards_banner_display")
diff --git a/app/views/publishers/home.html.slim b/app/views/publishers/home.html.slim
index 785e7fd990..fedc7056ef 100644
--- a/app/views/publishers/home.html.slim
+++ b/app/views/publishers/home.html.slim
@@ -9,7 +9,6 @@ noscript
current_publisher.uphold_verified? && \
current_publisher.wallet.present? && current_publisher.wallet.authorized? && \
(current_publisher.default_currency_confirmed_at.nil? || !current_publisher.default_currency.present?)
-
script type="text/html" id="confirm_default_currency_modal_wrapper"
= render :partial => 'confirm_default_currency_modal'
@@ -20,6 +19,13 @@ script type="text/html" id="confirm_default_currency_modal_wrapper"
class: 'title' \
)
= render partial: "choose_channel_button"
+ - if current_publisher.in_brave_rewards_whitelist?
+ = render partial: "instant_donation_button"
+
+= hidden_field_tag 'publisher_id', current_publisher.id
+= hidden_field_tag 'site-banner-react-props', (current_publisher&.site_banner&.read_only_react_property || {}).to_json
+/ TODO: (Albert Wang) Add conversion rate
+= hidden_field_tag 'conversion-rate', 0.3
.dashboard
#uphold_status { class=uphold_status_class(current_publisher)
@@ -349,3 +355,6 @@ javascript:
document.addEventListener('DOMContentLoaded', function() {
javascriptDetected();
});
+
+script id="instant-donation-selection" type="text/html"
+ = render "instant_donation_modal"
diff --git a/app/views/publishers/site_banners/new.html.slim b/app/views/publishers/site_banners/new.html.slim
new file mode 100644
index 0000000000..80383e14ab
--- /dev/null
+++ b/app/views/publishers/site_banners/new.html.slim
@@ -0,0 +1,2 @@
+= javascript_pack_tag("brave_rewards_banner_display")
+= hidden_field_tag 'publisher_id', current_publisher.id
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 0d7b06a5c3..163a4ad5b2 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -43,6 +43,9 @@
address: Rails.application.secrets[:smtp_server_address] || "127.0.0.1"
}
+ # Use S3 for storage
+ config.active_storage.service = :local
+
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 210d716078..ed294ecce0 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -87,6 +87,9 @@
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
+ # Use S3 for storage
+ config.active_storage.service = :amazon
+
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
diff --git a/config/environments/staging.rb b/config/environments/staging.rb
index dd4f577d81..d37d310f25 100644
--- a/config/environments/staging.rb
+++ b/config/environments/staging.rb
@@ -78,6 +78,9 @@
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
+ # Use S3 for storage
+ config.active_storage.service = :amazon
+
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 0805f74440..f19b5a709d 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -33,6 +33,8 @@ en:
download: Download
existing_account: Already have an account?
get_started: Get Started
+ instant_donation: Instant Donation
+ instant_donation_body: Instant Donation allows your fans to donate BAT at a set amount at the time of browsing your properties through the brand banner. This brand banner comes up when the user clicks the BAT icon next to the URL bar. Customize this brand banner with your own voice and image!
invalid_totp: Invalid 6-digit code. Please try again.
log_in: Log In
remove: Remove
diff --git a/config/routes.rb b/config/routes.rb
index ac1d843f01..9a042d6d45 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -40,7 +40,14 @@
resources :totp_authentications, only: %i(create)
resources :promo_registrations, only: %i(index create)
end
+ resources :site_banners, only: %i(new create), controller: 'publishers/site_banners' do
+ collection do
+ post :update_logo
+ post :update_background_image
+ end
+ end
end
+
devise_for :publishers, only: :omniauth_callbacks, controllers: { omniauth_callbacks: "publishers/omniauth_callbacks" }
resources :channels, only: %i(destroy) do
diff --git a/config/secrets.yml b/config/secrets.yml
index 74ef88e808..526971c94a 100644
--- a/config/secrets.yml
+++ b/config/secrets.yml
@@ -28,6 +28,7 @@ default: &default
basic_auth_password: <%= ENV["BASIC_AUTH_PASSWORD"] %>
basic_auth_user: <%= ENV["BASIC_AUTH_USER"] %>
fee_rate: <%= ENV["FEE_RATE"] %>
+ brave_rewards_email_whitelist: <%= ENV["BRAVE_REWARDS_EMAIL_WHITELIST"] %>
internal_email: <%= ENV["INTERNAL_EMAIL"] %>
# Piwik analytics endpoint with trailing slash e.g. https://piwik.example.com/
piwik_host: <%= ENV["PIWIK_HOST"] %>
diff --git a/config/storage.yml b/config/storage.yml
new file mode 100644
index 0000000000..7b13b0a8e4
--- /dev/null
+++ b/config/storage.yml
@@ -0,0 +1,14 @@
+amazon:
+ service: S3
+ access_key_id: <%= ENV['S3_REWARDS_ACCESS_KEY_ID'] %>
+ secret_access_key: <%= ENV['S3_REWARDS_SECRET_ACCESS_KEY'] %>
+ region: us-east-2
+ bucket: <%= ENV['S3_REWARDS_BUCKET_NAME'] %>
+
+local:
+ service: Disk
+ root: <%= Rails.root.join("storage") %>
+
+test:
+ service: Disk
+ root: <%= Rails.root.join("tmp/storage") %>
diff --git a/config/webpack/environment.js b/config/webpack/environment.js
index d16d9af743..e74f57146b 100644
--- a/config/webpack/environment.js
+++ b/config/webpack/environment.js
@@ -1,3 +1,5 @@
const { environment } = require('@rails/webpacker')
+const typescript = require('./loaders/typescript')
+environment.loaders.append('typescript', typescript)
module.exports = environment
diff --git a/config/webpack/loaders/typescript.js b/config/webpack/loaders/typescript.js
new file mode 100644
index 0000000000..9400260e1c
--- /dev/null
+++ b/config/webpack/loaders/typescript.js
@@ -0,0 +1,6 @@
+module.exports = {
+ test: /\.(ts|tsx)?(\.erb)?$/,
+ use: [{
+ loader: 'ts-loader'
+ }]
+}
diff --git a/config/webpacker.yml b/config/webpacker.yml
index f1bf267925..40a83bbefe 100644
--- a/config/webpacker.yml
+++ b/config/webpacker.yml
@@ -19,6 +19,7 @@ default: &default
- .js
- .jsx
- .ts
+ - .tsx
- .vue
- .sass
- .scss
diff --git a/package.json b/package.json
index 9426814c2a..bf52ac2da3 100644
--- a/package.json
+++ b/package.json
@@ -5,8 +5,18 @@
},
"dependencies": {
"@rails/webpacker": "3.5",
+ "@types/react": "^16.4.7",
+ "@types/react-dom": "^16.0.6",
+ "babel-preset-react": "^6.24.1",
+ "brave-ui": "0.23.0",
"clipboard": "^1.7.1",
- "rails-ujs": "^5.1.4"
+ "prop-types": "^15.6.2",
+ "rails-ujs": "^5.1.4",
+ "react": "^16.4.1",
+ "react-dom": "^16.4.1",
+ "styled-components": "^3.2.6",
+ "ts-loader": "3.5.0",
+ "typescript": "^2.9.2"
},
"devDependencies": {
"hoek": "^5.0.3",
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000000..7425c2b4b1
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "declaration": false,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "lib": ["es6", "dom"],
+ "module": "es6",
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "target": "es5",
+ "jsx": "react"
+ },
+ "exclude": [
+ "**/*.spec.ts",
+ "node_modules",
+ "vendor",
+ "public"
+ ],
+ "compileOnSave": false
+}
diff --git a/yarn.lock b/yarn.lock
index 5cde6720f8..9b6e2f2bf3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -32,6 +32,23 @@
webpack "^3.12.0"
webpack-manifest-plugin "^1.3.2"
+"@types/node@*":
+ version "10.5.4"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.4.tgz#6eccc158504357d1da91434d75e86acde94bb10b"
+
+"@types/react-dom@^16.0.6":
+ version "16.0.6"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.6.tgz#f1a65a4e7be8ed5d123f8b3b9eacc913e35a1a3c"
+ dependencies:
+ "@types/node" "*"
+ "@types/react" "*"
+
+"@types/react@*", "@types/react@^16.4.7":
+ version "16.4.7"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.7.tgz#f33f6d759a7e1833befa15224d68942d178a5a3f"
+ dependencies:
+ csstype "^2.2.0"
+
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@@ -248,6 +265,10 @@ arraybuffer.slice@~0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
+asap@~2.0.3:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
+
asn1.js@^4.0.0:
version "4.9.2"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a"
@@ -435,6 +456,14 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
+babel-helper-builder-react-jsx@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ esutils "^2.0.2"
+
babel-helper-call-delegate@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d"
@@ -564,6 +593,14 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
+babel-plugin-syntax-flow@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
+
+babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
+
babel-plugin-syntax-object-rest-spread@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
@@ -765,6 +802,13 @@ babel-plugin-transform-exponentiation-operator@^6.22.0:
babel-plugin-syntax-exponentiation-operator "^6.8.0"
babel-runtime "^6.22.0"
+babel-plugin-transform-flow-strip-types@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf"
+ dependencies:
+ babel-plugin-syntax-flow "^6.18.0"
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-object-rest-spread@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06"
@@ -772,6 +816,34 @@ babel-plugin-transform-object-rest-spread@^6.26.0:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.26.0"
+babel-plugin-transform-react-display-name@^6.23.0:
+ version "6.25.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-react-jsx-self@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e"
+ dependencies:
+ babel-plugin-syntax-jsx "^6.8.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-react-jsx-source@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6"
+ dependencies:
+ babel-plugin-syntax-jsx "^6.8.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-react-jsx@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3"
+ dependencies:
+ babel-helper-builder-react-jsx "^6.24.1"
+ babel-plugin-syntax-jsx "^6.8.0"
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-regenerator@^6.22.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f"
@@ -828,6 +900,23 @@ babel-preset-env@^1.7.0:
invariant "^2.2.2"
semver "^5.3.0"
+babel-preset-flow@^6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d"
+ dependencies:
+ babel-plugin-transform-flow-strip-types "^6.22.0"
+
+babel-preset-react@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380"
+ dependencies:
+ babel-plugin-syntax-jsx "^6.3.13"
+ babel-plugin-transform-react-display-name "^6.23.0"
+ babel-plugin-transform-react-jsx "^6.24.1"
+ babel-plugin-transform-react-jsx-self "^6.22.0"
+ babel-plugin-transform-react-jsx-source "^6.22.0"
+ babel-preset-flow "^6.23.0"
+
babel-register@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
@@ -905,8 +994,8 @@ base64-arraybuffer@0.1.5:
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
base64-js@^1.0.2:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
base64id@1.0.0:
version "1.0.0"
@@ -1073,6 +1162,12 @@ braces@^2.3.0, braces@^2.3.1:
split-string "^3.0.2"
to-regex "^3.0.1"
+brave-ui@0.23.0:
+ version "0.23.0"
+ resolved "https://registry.yarnpkg.com/brave-ui/-/brave-ui-0.23.0.tgz#4e847b9eb8ffa4c1ca5140f75e07a0b9029ad51c"
+ dependencies:
+ emptykit.css "^1.0.1"
+
brorand@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -1170,6 +1265,13 @@ buffer@^4.3.0:
ieee754 "^1.1.4"
isarray "^1.0.0"
+buffer@^5.0.3:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.0.tgz#53cf98241100099e9eeae20ee6d51d21b16e541e"
+ dependencies:
+ base64-js "^1.0.2"
+ ieee754 "^1.1.4"
+
buildmail@4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/buildmail/-/buildmail-4.0.1.tgz#877f7738b78729871c9a105e3b837d2be11a7a72"
@@ -1673,6 +1775,10 @@ copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+core-js@^1.0.0:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
core-js@^2.2.0:
version "2.5.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
@@ -1773,6 +1879,10 @@ css-color-function@~1.3.3:
debug "^3.1.0"
rgb "~0.1.0"
+css-color-keywords@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
+
css-color-names@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@@ -1804,6 +1914,14 @@ css-selector-tokenizer@^0.7.0:
fastparse "^1.1.1"
regexpu-core "^1.0.0"
+css-to-react-native@^2.0.3:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.2.1.tgz#7f3f4c95de65501b8720c87bf0caf1f39073b88e"
+ dependencies:
+ css-color-keywords "^1.0.0"
+ fbjs "^0.8.5"
+ postcss-value-parser "^3.3.0"
+
css-unit-converter@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996"
@@ -1856,6 +1974,10 @@ csso@~2.3.1:
clap "^1.0.9"
source-map "^0.5.3"
+csstype@^2.2.0:
+ version "2.5.6"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.5.6.tgz#2ae1db2319642d8b80a668d2d025c6196071e788"
+
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -2123,10 +2245,20 @@ emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+emptykit.css@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/emptykit.css/-/emptykit.css-1.0.1.tgz#e7c592c9c4bbe9b358411eb50e5011719a89f512"
+
encodeurl@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
+encoding@^0.1.11:
+ version "0.1.12"
+ resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+ dependencies:
+ iconv-lite "~0.4.13"
+
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206"
@@ -2172,7 +2304,7 @@ engine.io@~3.1.0:
optionalDependencies:
uws "~9.14.0"
-enhanced-resolve@^3.4.0:
+enhanced-resolve@^3.0.0, enhanced-resolve@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
dependencies:
@@ -2565,6 +2697,18 @@ faye-websocket@~0.11.0:
dependencies:
websocket-driver ">=0.5.1"
+fbjs@^0.8.16, fbjs@^0.8.5:
+ version "0.8.17"
+ resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
+ dependencies:
+ core-js "^1.0.0"
+ isomorphic-fetch "^2.1.1"
+ loose-envify "^1.0.0"
+ object-assign "^4.1.0"
+ promise "^7.1.1"
+ setimmediate "^1.0.5"
+ ua-parser-js "^0.7.18"
+
file-loader@^1.1.11:
version "1.1.11"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-1.1.11.tgz#6fe886449b0f2a936e43cabaac0cdbfb369506f8"
@@ -3144,6 +3288,10 @@ hoek@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-5.0.3.tgz#b71d40d943d0a95da01956b547f83c4a5b4a34ac"
+hoist-non-react-statics@^2.5.0:
+ version "2.5.5"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
+
home-or-tmp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
@@ -3281,7 +3429,7 @@ iconv-lite@0.4.19:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
-iconv-lite@0.4.23, iconv-lite@^0.4.4:
+iconv-lite@0.4.23, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
version "0.4.23"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
dependencies:
@@ -3298,8 +3446,8 @@ icss-utils@^2.1.0:
postcss "^6.0.1"
ieee754@^1.1.4:
- version "1.1.8"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b"
iferr@^0.1.5:
version "0.1.5"
@@ -3628,7 +3776,7 @@ is-regex@^1.0.4:
dependencies:
has "^1.0.1"
-is-stream@^1.1.0:
+is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@@ -3692,6 +3840,13 @@ isobject@^3.0.0, isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+isomorphic-fetch@^2.1.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+ dependencies:
+ node-fetch "^1.0.1"
+ whatwg-fetch ">=0.10.0"
+
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
@@ -3704,7 +3859,11 @@ js-reporters@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b"
-js-tokens@^3.0.0, js-tokens@^3.0.2:
+"js-tokens@^3.0.0 || ^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+
+js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
@@ -4062,11 +4221,11 @@ longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
-loose-envify@^1.0.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
dependencies:
- js-tokens "^3.0.0"
+ js-tokens "^3.0.0 || ^4.0.0"
loud-rejection@^1.0.0, loud-rejection@^1.6.0:
version "1.6.0"
@@ -4438,6 +4597,13 @@ netmask@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
+node-fetch@^1.0.1:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
+ dependencies:
+ encoding "^0.1.11"
+ is-stream "^1.0.1"
+
node-forge@0.6.33:
version "0.6.33"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc"
@@ -5598,12 +5764,25 @@ promise-inflight@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
+promise@^7.1.1:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
+ dependencies:
+ asap "~2.0.3"
+
promisify-call@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/promisify-call/-/promisify-call-2.0.4.tgz#d48c2d45652ccccd52801ddecbd533a6d4bd5fba"
dependencies:
with-callback "^1.0.2"
+prop-types@^15.5.4, prop-types@^15.6.0, prop-types@^15.6.2:
+ version "15.6.2"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
+ dependencies:
+ loose-envify "^1.3.1"
+ object-assign "^4.1.1"
+
proxy-addr@~2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec"
@@ -5803,6 +5982,28 @@ rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
+react-dom@^16.4.1:
+ version "16.4.1"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.1.tgz#7f8b0223b3a5fbe205116c56deb85de32685dad6"
+ dependencies:
+ fbjs "^0.8.16"
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+ prop-types "^15.6.0"
+
+react-is@^16.3.1:
+ version "16.4.2"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.2.tgz#84891b56c2b6d9efdee577cc83501dfc5ecead88"
+
+react@^16.4.1:
+ version "16.4.1"
+ resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32"
+ dependencies:
+ fbjs "^0.8.16"
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+ prop-types "^15.6.0"
+
read-cache@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
@@ -6290,7 +6491,7 @@ selfsigned@^1.9.1:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
-semver@^5.5.0:
+semver@^5.0.1, semver@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
@@ -6367,7 +6568,7 @@ set-value@^2.0.0:
is-plain-object "^2.0.3"
split-string "^3.0.1"
-setimmediate@^1.0.4:
+setimmediate@^1.0.4, setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
@@ -6815,6 +7016,28 @@ style-loader@^0.21.0:
loader-utils "^1.1.0"
schema-utils "^0.4.5"
+styled-components@^3.2.6:
+ version "3.4.2"
+ resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.4.2.tgz#8f518419932327e47fe9144824e3184b3e2da95d"
+ dependencies:
+ buffer "^5.0.3"
+ css-to-react-native "^2.0.3"
+ fbjs "^0.8.16"
+ hoist-non-react-statics "^2.5.0"
+ prop-types "^15.5.4"
+ react-is "^16.3.1"
+ stylis "^3.5.0"
+ stylis-rule-sheet "^0.0.10"
+ supports-color "^3.2.3"
+
+stylis-rule-sheet@^0.0.10:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"
+
+stylis@^3.5.0:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.3.tgz#99fdc46afba6af4deff570825994181a5e6ce546"
+
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@@ -6985,6 +7208,16 @@ trim-right@^1.0.1:
dependencies:
glob "^6.0.4"
+ts-loader@3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-3.5.0.tgz#151d004dcddb4cf8e381a3bf9d6b74c2d957a9c0"
+ dependencies:
+ chalk "^2.3.0"
+ enhanced-resolve "^3.0.0"
+ loader-utils "^1.0.2"
+ micromatch "^3.1.4"
+ semver "^5.0.1"
+
tsscmp@~1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.5.tgz#7dc4a33af71581ab4337da91d85ca5427ebd9a97"
@@ -7031,6 +7264,14 @@ typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+typescript@^2.9.2:
+ version "2.9.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
+
+ua-parser-js@^0.7.18:
+ version "0.7.18"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"
+
uglify-es@^3.3.4:
version "3.3.9"
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
@@ -7388,6 +7629,10 @@ websocket-extensions@>=0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
+whatwg-fetch@>=0.10.0:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
+
when@^3.7.7:
version "3.7.8"
resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82"