diff --git a/.circleci/config.yml b/.circleci/config.yml
index fa5d8dad8d3..87bf7e2b52a 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -2,7 +2,7 @@ version: 2.0
jobs:
acceptance:
docker:
- - image: circleci/node:8-stretch-browsers
+ - image: circleci/node:10-stretch-browsers
parallelism: 1
steps:
- add_ssh_keys
@@ -44,7 +44,7 @@ jobs:
hokusai registry push --tag $CIRCLE_SHA1 --force --overwrite
publish_staging_assets:
docker:
- - image: circleci/node:8-stretch-browsers
+ - image: circleci/node:10-stretch-browsers
steps:
- add_ssh_keys
- checkout
@@ -58,7 +58,7 @@ jobs:
- manifest.json
publish_release_assets:
docker:
- - image: circleci/node:8-stretch-browsers
+ - image: circleci/node:10-stretch-browsers
steps:
- add_ssh_keys
- checkout
diff --git a/.nvmrc b/.nvmrc
index ef59ed7f567..4e31022509a 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-8.12
+10.13
diff --git a/.prettierignore b/.prettierignore
index 764f8b23876..7d4e8e8f54d 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1 +1,2 @@
__generated__
+src/desktop/components/react/stitch_components/index.tsx
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 71af3f0732a..914f8fa0ab9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -18,11 +18,11 @@ git remote add upstream https://github.com/artsy/force.git
## Run Force
-Install [NVM](https://github.com/creationix/nvm) and Node 8.
+Install [NVM](https://github.com/creationix/nvm) and Node 10.
```sh
-nvm install 8
-nvm alias default 8
+nvm install 10
+nvm alias default 10
```
Install node modules with Yarn.
diff --git a/Dockerfile b/Dockerfile
index 724a28448e7..d363e078502 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:8.12.0
+FROM node:10.14.1
ARG commit_hash
RUN test -n "$commit_hash"
diff --git a/app.json b/app.json
index 5e6a0d13bfe..a0999268e4f 100644
--- a/app.json
+++ b/app.json
@@ -179,9 +179,6 @@
"METAPHYSICS_ENDPOINT": {
"required": true
},
- "MIXPANEL_ID": {
- "required": true
- },
"MOBILE_MARKETING_SIGNUP_MODALS": {
"required": true
},
diff --git a/docs/images/echo_manifest.png b/docs/images/echo_manifest.png
new file mode 100644
index 00000000000..94090e15b33
Binary files /dev/null and b/docs/images/echo_manifest.png differ
diff --git a/docs/images/hokusai_images.png b/docs/images/hokusai_images.png
new file mode 100644
index 00000000000..85c36cc453d
Binary files /dev/null and b/docs/images/hokusai_images.png differ
diff --git a/docs/images/single_image.png b/docs/images/single_image.png
new file mode 100644
index 00000000000..f16b60171c3
Binary files /dev/null and b/docs/images/single_image.png differ
diff --git a/docs/rolling_back.md b/docs/rolling_back.md
new file mode 100644
index 00000000000..58fea62d5cc
--- /dev/null
+++ b/docs/rolling_back.md
@@ -0,0 +1,23 @@
+## How to Rollback (on Kubernetes, deployed w/ Hokusai)
+
+So, you're reading this doc, in which case either nothing is on fire and you're simply educating yourself (yay!), or, there's a problem and you need to rollback Force. Take a deep breath, and read on.
+
+1. Run `hokusai registry images`. You'll see output like the below.
+
+![list of images](images/hokusai_images.png "Hokusai Images")
+
+2. Locate the name of a tag you want to deploy. In this case, since we're rolling back, it'll be the previous tag of the form `production-YYYY-mm-dd..`
+
+![specific image](images/single_image.png "Last Prod Image")
+
+3. Locate the Circle CI deploy process that corresponded to the deploy you are rolling back to. You may need to scroll back in the build history until you find it. One such example is: https://circleci.com/workflow-run/9fec809a-d096-4fc0-88b7-82419ada519d
+
+4. Open up the final step, `deploy_hokusai_production`, and expand the 'Echo Manifest' step. This is a config variable that changes with each deploy, and needs to be set manually during the rollback.
+
+![echo manifest](images/echo_manifest.png "Echo Manifest")
+
+5. Copy the long value into a text editor, and add single quotes around the entire thing. Then copy it to your clipboard.
+
+6. Run the following command to set the config in the environment. `hokusai production env set ASSET_MANIFEST=...clipboard contents...`
+
+7. When that completes, run the following command to deploy the desired image that you've located above. `hokusai production deploy production--2018-11-21--20-05-37`
diff --git a/package.json b/package.json
index a393db278c9..23ddce2bda1 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "1.0.0",
"private": true,
"engines": {
- "node": "8.12.x",
+ "node": "10",
"yarn": "1.x.x"
},
"scripts": {
@@ -50,11 +50,12 @@
"react-relay": "https://github.com/alloy/relay/releases/download/v1.5.0-artsy.5/react-relay-1.5.0-artsy.5.tgz"
},
"dependencies": {
- "@artsy/express-reloadable": "^1.3.1",
- "@artsy/palette": "^2.18.1",
- "@artsy/passport": "^1.1.0",
- "@artsy/reaction": "^6.1.8",
- "@artsy/stitch": "^2.0.0",
+ "@airbnb/node-memwatch": "^1.0.2",
+ "@artsy/express-reloadable": "1.4.0",
+ "@artsy/palette": "2.23.2",
+ "@artsy/passport": "1.1.0",
+ "@artsy/reaction": "9.1.12",
+ "@artsy/stitch": "3.1.0",
"@babel/core": "^7.0.0",
"@babel/node": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.0.0",
@@ -98,7 +99,7 @@
"bem-cn-lite": "^3.0.0",
"bluebird": "^3.4.6",
"bluebird-q": "^2.1.1",
- "blueimp-file-upload": "9.9.0",
+ "blueimp-file-upload": "9.22.1",
"body-parser": "^1.14.1",
"bucket-assets": "^1.0.2",
"chalk": "^2.4.1",
@@ -158,7 +159,6 @@
"lodash.isinteger": "^4.0.4",
"lodash.merge": "^4.6.0",
"mailcheck": "^1.1.1",
- "memwatch-ng": "^1.2.0",
"moment": "~2.16.0",
"moment-timezone": "^0.5.5",
"moment-twitter": "^0.2.0",
@@ -238,6 +238,7 @@
"@types/react-dom": "^16.0.7",
"@types/styled-system": "^3.0.4",
"@types/webpack": "^4.4.11",
+ "@types/webpack-env": "^1.13.6",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^23.6.0",
"benv": "^3.3.0",
@@ -245,7 +246,7 @@
"coffee-loader": "^0.8.0",
"core-js": "^2.5.7",
"danger": "^6.0.2",
- "electron": "1.7.8",
+ "electron": "1.7.16",
"enzyme": "^3.4.4",
"enzyme-adapter-react-16": "^1.5.0",
"eslint": "^5.6.1",
@@ -265,7 +266,7 @@
"husky": "^0.14.3",
"imagesloaded": "^4.1.1",
"inquirer": "^1.2.3",
- "jest": "^23.5.2",
+ "jest": "^23.6.0",
"jest-coffee-preprocessor": "^1.0.0",
"jsdom": "^11.0.0",
"jsdom-global": "^3.0.2",
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 00000000000..a786489dd2b
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,10 @@
+{
+ "extends": [
+ "@artsy"
+ ],
+ "assignees": [
+ "zephraph",
+ "damassi",
+ "sweir27"
+ ]
+}
diff --git a/src/desktop/analytics/README.md b/src/desktop/analytics/README.md
index 6bc6d55fc43..137ac7e80d8 100644
--- a/src/desktop/analytics/README.md
+++ b/src/desktop/analytics/README.md
@@ -139,7 +139,7 @@ Open Chrome dev tools `cmd + opt + i`, click on the "Network" tab, click the "Fi
![](https://s3.amazonaws.com/f.cl.ly/items/2Z2K0X1E3d0O141D1d1n/Image%202015-04-14%20at%201.09.48%20PM.png)
-Filter the calls according the service you need to debug by typing in the "Filter" input on the left, e.g. "mixpanel". Then click on a network call you think is reponsible for the even you want to track. This will bring up a panel that looks like this:
+Filter the calls according the service you need to debug by typing in the "Filter" input on the left, e.g. "segment". Then click on a network call you think is reponsible for the even you want to track. This will bring up a panel that looks like this:
![](https://s3.amazonaws.com/f.cl.ly/items/1p3M3N3o3O3z0s0P2C28/Image%202015-04-14%20at%201.20.24%20PM.png)
diff --git a/src/desktop/analytics/criteo.js b/src/desktop/analytics/criteo.js
index 5015406bc71..9153b392996 100644
--- a/src/desktop/analytics/criteo.js
+++ b/src/desktop/analytics/criteo.js
@@ -63,7 +63,7 @@ if (pathSplit[1] === "auctions") {
)
} else {
window.criteo_q.push(
- { event: "setAccount", account: sd.CRITEO_ARTWORKS_ACCOUNT_NUMBER },
+ { event: "setAccount", account: sd.CRITEO_AUCTIONS_ACCOUNT_NUMBER },
{ event: "setSiteType", type: "d" },
{ event: "setEmail", email: userEmail },
{ event: "viewItem", item: sd.COMMERCIAL.artwork._id }
@@ -72,7 +72,7 @@ if (pathSplit[1] === "auctions") {
// ARTWORKS viewBasket
analyticsHooks.on("inquiry_questionnaire:modal:opened", function(data) {
window.criteo_q.push(
- { event: "setAccount", account: sd.CRITEO_ARTWORKS_ACCOUNT_NUMBER },
+ { event: "setAccount", account: sd.CRITEO_AUCTIONS_ACCOUNT_NUMBER },
{ event: "setSiteType", type: "d" },
{ event: "setEmail", email: userEmail },
{
@@ -90,7 +90,7 @@ if (pathSplit[1] === "auctions") {
// ARTWORKS trackTransaction
analyticsHooks.on("inquiry_questionnaire:inquiry:sync", function(data) {
window.criteo_q.push(
- { event: "setAccount", account: sd.CRITEO_ARTWORKS_ACCOUNT_NUMBER },
+ { event: "setAccount", account: sd.CRITEO_AUCTIONS_ACCOUNT_NUMBER },
{ event: "setSiteType", type: "d" },
{ event: "setEmail", email: userEmail },
{
@@ -111,7 +111,7 @@ if (pathSplit[1] === "auctions") {
// https://www.artsy.net/collect - (ARTWORKS viewHome)
// 0 1
window.criteo_q.push(
- { event: "setAccount", account: sd.CRITEO_ARTWORKS_ACCOUNT_NUMBER },
+ { event: "setAccount", account: sd.CRITEO_AUCTIONS_ACCOUNT_NUMBER },
{ event: "setSiteType", type: "d" },
{ event: "setEmail", email: userEmail },
{ event: "viewHome" }
diff --git a/src/desktop/apps/article/__tests__/routes.test.js b/src/desktop/apps/article/__tests__/routes.test.js
index a942fd23568..ab06ad8222b 100644
--- a/src/desktop/apps/article/__tests__/routes.test.js
+++ b/src/desktop/apps/article/__tests__/routes.test.js
@@ -6,7 +6,14 @@ import Channel from "desktop/models/channel.coffee"
import { getCurrentUnixTimestamp } from "reaction/Components/Publishing/Constants"
const rewire = require("rewire")("../routes")
-const { amp, classic, editorialSignup, index, subscribedToEditorial } = rewire
+const {
+ amp,
+ classic,
+ editorialSignup,
+ index,
+ isCustomEditorial,
+ subscribedToEditorial,
+} = rewire
describe("Article Routes", () => {
let req
@@ -39,6 +46,7 @@ describe("Article Routes", () => {
rewire.__set__("sd", {
ARTSY_EDITORIAL_CHANNEL: "123",
APP_URL: "https://artsy.net",
+ EOY_2018_ARTISTS: "5bf30690d8b9430baaf6c6de",
}),
rewire.__set__("sailthru", {
apiPost: sailthruApiPost,
@@ -388,6 +396,39 @@ describe("Article Routes", () => {
})
})
})
+
+ describe("Custom editorial", () => {
+ it("#isCustomEditorial returns key if article.id matches custom editorial list", () => {
+ isCustomEditorial("5bf30690d8b9430baaf6c6de").should.containEql(
+ "EOY_2018_ARTISTS"
+ )
+ })
+
+ it("Adds custom editorial var and no-header class to stitch args", done => {
+ const data = {
+ article: _.extend({}, fixtures.article, {
+ slug: "foobar",
+ channel_id: "123",
+ layout: "feature",
+ id: "5bf30690d8b9430baaf6c6de",
+ }),
+ }
+ rewire.__set__(
+ "positronql",
+ sinon.stub().returns(Promise.resolve(data))
+ )
+ const stitch = sinon.stub()
+ rewire.__set__("stitch", stitch)
+ req.path = "/article/foobar"
+ index(req, res, next).then(() => {
+ stitch.args[0][0].locals.bodyClass.should.containEql("body-no-header")
+ stitch.args[0][0].data.customEditorial.should.containEql(
+ "EOY_2018_ARTISTS"
+ )
+ done()
+ })
+ })
+ })
})
describe("#classic", () => {
diff --git a/src/desktop/apps/article/components/App.js b/src/desktop/apps/article/components/App.js
index ba11b460c74..45e59ddee9e 100644
--- a/src/desktop/apps/article/components/App.js
+++ b/src/desktop/apps/article/components/App.js
@@ -16,6 +16,7 @@ export default hot(module)(
class App extends React.Component {
static propTypes = {
article: PropTypes.object,
+ customEditorial: PropTypes.string,
}
getArticleLayout = () => {
diff --git a/src/desktop/apps/article/components/layouts/Article.tsx b/src/desktop/apps/article/components/layouts/Article.tsx
index b2f0298304f..df34cea4036 100644
--- a/src/desktop/apps/article/components/layouts/Article.tsx
+++ b/src/desktop/apps/article/components/layouts/Article.tsx
@@ -1,8 +1,9 @@
import React from "react"
import { once } from "lodash"
-
-import { Article } from "reaction/Components/Publishing"
-import { ArticleProps } from "reaction/Components/Publishing/Article"
+import {
+ Article,
+ ArticleProps,
+} from "@artsy/reaction/dist/Components/Publishing/Article"
import {
ModalOptions,
ModalType,
@@ -108,6 +109,7 @@ export default class ArticleLayout extends React.Component<
render() {
const {
article,
+ customEditorial,
isSuper,
isLoggedIn,
isMobile,
@@ -116,7 +118,7 @@ export default class ArticleLayout extends React.Component<
templates: { SuperArticleFooter, SuperArticleHeader } = {} as any,
} = this.props
- const isStatic = isSuper || article.seriesArticle
+ const isStatic = isSuper || article.seriesArticle || customEditorial
return (
@@ -131,6 +133,7 @@ export default class ArticleLayout extends React.Component<
{isStatic ? (
{
const isSuper = article.is_super_article || article.is_super_sub_article
const isFullscreen =
article.hero_section && article.hero_section.type === "fullscreen"
- if (isSuper && isFullscreen) {
+ if ((isSuper && isFullscreen) || isCustomEditorial(article.id)) {
bodyClass = bodyClass + " body-no-header"
}
return bodyClass
@@ -318,3 +325,13 @@ export const editorialSignup = (req, res, next) => {
export const redirectPost = (req, res, next) =>
res.redirect(301, req.url.replace("post", "article"))
+
+export const isCustomEditorial = id => {
+ const customIds = [sd.EOY_2018_ARTISTS, sd.EOY_2018_CULTURE]
+
+ if (customIds.includes(id)) {
+ return findKey(sd, val => {
+ return val === id
+ })
+ }
+}
diff --git a/src/desktop/apps/article/templates/meta.jade b/src/desktop/apps/article/templates/meta.jade
index c82044ad250..690cd24eb99 100644
--- a/src/desktop/apps/article/templates/meta.jade
+++ b/src/desktop/apps/article/templates/meta.jade
@@ -82,3 +82,7 @@ link( rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/l
//- Set Viewport scale
meta( name="viewport", content="width=device-width, initial-scale=1.0" )
+
+
+style
+ =sd.RESPONSIVE_CSS
diff --git a/src/desktop/apps/artist/client.js b/src/desktop/apps/artist/client.tsx
similarity index 96%
rename from src/desktop/apps/artist/client.js
rename to src/desktop/apps/artist/client.tsx
index 35a1c0e12a0..9324d543e10 100644
--- a/src/desktop/apps/artist/client.js
+++ b/src/desktop/apps/artist/client.tsx
@@ -1,20 +1,13 @@
import { buildClientApp } from "reaction/Artsy/Router/client"
import { data as sd } from "sharify"
import { routes } from "reaction/Apps/Artist/routes"
-import mediator from "desktop/lib/mediator.coffee"
import React from "react"
import ReactDOM from "react-dom"
import styled from "styled-components"
import qs from "querystring"
import { clone, isArray } from "underscore"
-mediator.on("artist:filter:changed", filters => {
- onFilterChange(filters)
-})
-
-mediator.on("artist:tabclick", ({ to }) => {
- window.analytics.page({ path: to }, { integrations: { Marketo: false } })
-})
+const mediator = require("desktop/lib/mediator.coffee")
buildClientApp({
routes,
@@ -40,6 +33,14 @@ if (module.hot) {
module.hot.accept()
}
+mediator.on("artist:filter:changed", filters => {
+ onFilterChange(filters)
+})
+
+mediator.on("artist:tabclick", ({ to }) => {
+ window.analytics.page({ path: to }, { integrations: { Marketo: false } })
+})
+
// Update URL with current filters and sort.
const onFilterChange = filters => {
const params = clone(filters)
diff --git a/src/desktop/apps/artist/server.js b/src/desktop/apps/artist/server.js
deleted file mode 100644
index d74a35f5c36..00000000000
--- a/src/desktop/apps/artist/server.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { buildServerApp } from "reaction/Artsy/Router/server"
-import { Meta, query, toJSONLD } from "./components/Meta"
-import { stitch } from "@artsy/stitch"
-import { routes } from "reaction/Apps/Artist/routes"
-import express from "express"
-import metaphysics from "lib/metaphysics.coffee"
-import React from "react"
-import styled from "styled-components"
-import { buildServerAppContext } from "desktop/lib/buildServerAppContext"
-
-const app = (module.exports = express())
-
-app.get("/artist/:artistID*", async (req, res, next) => {
- try {
- const user = req.user && req.user.toJSON()
-
- const { ServerApp, redirect, status } = await buildServerApp({
- routes,
- url: req.url,
- context: buildServerAppContext(req, res),
- })
-
- if (redirect) {
- res.redirect(302, redirect.url)
- return
- }
-
- // FIXME: Move this to Reaction
- const Container = styled.div`
- width: 100%;
- max-width: 1192px;
- margin: auto;
- `
-
- const send = {
- method: "post",
- query,
- variables: { artistID: req.params.artistID },
- }
-
- const { artist } = await metaphysics(send).then(data => data)
- const { APP_URL, IS_MOBILE, REFERRER } = res.locals.sd
- const isExternalReferer = !(REFERRER && REFERRER.includes(APP_URL))
- const jsonLD = toJSONLD(artist, APP_URL)
-
- res.locals.sd.ARTIST_PAGE_CTA_ENABLED =
- !user && isExternalReferer && !IS_MOBILE
- res.locals.sd.ARTIST_PAGE_CTA_ARTIST_ID = req.params.artistID
-
- // Render layout
- const layout = await stitch({
- basePath: __dirname,
- layout: "../../components/main_layout/templates/react_redesign.jade",
- config: {
- styledComponents: true,
- },
- blocks: {
- head: () => ,
- body: () => (
-
-
-
- ),
- },
- locals: {
- ...res.locals,
- assetPackage: "artist",
- },
- data: {
- jsonLD,
- },
- })
-
- res.status(status).send(layout)
- } catch (error) {
- console.log(error)
- next(error)
- }
-})
-
-export default app
diff --git a/src/desktop/apps/artist/server.tsx b/src/desktop/apps/artist/server.tsx
new file mode 100644
index 00000000000..6dde288f7b6
--- /dev/null
+++ b/src/desktop/apps/artist/server.tsx
@@ -0,0 +1,96 @@
+import { buildServerApp } from "reaction/Artsy/Router/server"
+import { Meta, query, toJSONLD } from "./components/Meta"
+import { stitch } from "@artsy/stitch"
+import { routes } from "reaction/Apps/Artist/routes"
+import React from "react"
+import styled from "styled-components"
+import { buildServerAppContext } from "desktop/lib/buildServerAppContext"
+import express, { Request, Response, NextFunction } from "express"
+
+const metaphysics = require("lib/metaphysics.coffee")
+
+export const app = express()
+
+app.get(
+ "/artist/:artistID*",
+ async (req: Request, res: Response, next: NextFunction) => {
+ try {
+ const user = req.user && req.user.toJSON()
+
+ const {
+ ServerApp,
+ redirect,
+ status,
+ headTags,
+ scripts,
+ } = await buildServerApp({
+ routes,
+ url: req.url,
+ userAgent: req.header("User-Agent"),
+ context: buildServerAppContext(req, res),
+ })
+
+ if (redirect) {
+ res.redirect(302, redirect.url)
+ return
+ }
+
+ // FIXME: Move this to Reaction
+ const Container = styled.div`
+ width: 100%;
+ max-width: 1192px;
+ margin: auto;
+ `
+
+ const send = {
+ method: "post",
+ query,
+ variables: { artistID: req.params.artistID },
+ }
+
+ const { artist } = await metaphysics(send).then(data => data)
+ const { APP_URL, IS_MOBILE, REFERRER } = res.locals.sd
+ const isExternalReferer = !(REFERRER && REFERRER.includes(APP_URL))
+ const jsonLD = toJSONLD(artist, APP_URL)
+
+ res.locals.sd.ARTIST_PAGE_CTA_ENABLED =
+ !user && isExternalReferer && !IS_MOBILE
+ res.locals.sd.ARTIST_PAGE_CTA_ARTIST_ID = req.params.artistID
+
+ // Render layout
+ const layout = await stitch({
+ basePath: __dirname,
+ layout: "../../components/main_layout/templates/react_redesign.jade",
+ config: {
+ styledComponents: true,
+ },
+ blocks: {
+ head: () => (
+ <>
+ {headTags}
+
+ >
+ ),
+ body: () => (
+
+
+
+ ),
+ },
+ locals: {
+ ...res.locals,
+ assetPackage: "artist",
+ scripts,
+ },
+ data: {
+ jsonLD,
+ },
+ })
+
+ res.status(status).send(layout)
+ } catch (error) {
+ console.log(error)
+ next(error)
+ }
+ }
+)
diff --git a/src/desktop/apps/artsy_in_miami/components/MiamiFairWeekPage.js b/src/desktop/apps/artsy_in_miami/components/MiamiFairWeekPage.js
index 186d37150b8..1a557b8c87e 100644
--- a/src/desktop/apps/artsy_in_miami/components/MiamiFairWeekPage.js
+++ b/src/desktop/apps/artsy_in_miami/components/MiamiFairWeekPage.js
@@ -86,7 +86,7 @@ export default ({
diff --git a/src/desktop/apps/artsy_in_miami/fixture.json b/src/desktop/apps/artsy_in_miami/fixture.json
index 10d932a998b..39f3e6d0ccd 100644
--- a/src/desktop/apps/artsy_in_miami/fixture.json
+++ b/src/desktop/apps/artsy_in_miami/fixture.json
@@ -1,68 +1,81 @@
{
+ "meta": {
+ "title": "Art Basel and more on Artsy | Miami Week 2018",
+ "description": "Artsy is your guide to Miami Week 2018. Explore the fairs, editorial coverage, Artsy events, and more—all in one place. December 4-9."
+ },
"introduction": {
- "title": "Miami Week
Dec 4-10, 2017",
- "description": "For one week a year, Miami becomes a global destination for art, design, music and all things visual culture. Each fair brings together the most influential collectors, gallerists, designers, curators and critics from around the world in celebration of design culture and commerce."
+ "title": "Miami Art Week
Dec 4–9, 2018",
+ "description": "For one week a year, Miami becomes a global destination for art, design, music, and all things visual culture. Celebrate the year in art as collectors, art lovers, and curators come together for the most talked-about art fairs, openings, and events.",
+ "image": "https://d3vpvtm3t56z1n.cloudfront.net/images/hero.jpg"
},
"fair_coverage": {
- "title": "Visit the fairs",
+ "title": "Fair coverage launches November 28",
"fairs": [
{
- "logo_url": "https://d3vpvtm3t56z1n.cloudfront.net/images/artb.jpg",
- "site_url": "https://www.google.com"
+ "logo_url": "https://artsy-media-uploads.s3.amazonaws.com/1VDIT3dxaBp8gPPti_ms9g/Group%2019%402x.png",
+ "site_url": "https://www.artsy.net/art-basel-in-miami-beach-2018"
+ },
+ {
+ "logo_url": "https://artsy-media-uploads.s3.amazonaws.com/ZCfE2UxeGuBpXGZyzbMiFA/INK%20Miami.png",
+ "site_url": "https://www.artsy.net/ink-miami-2018"
+ },
+ {
+ "logo_url": "https://artsy-media-uploads.s3.amazonaws.com/smTFa2LbpHyYltL5BnKpDA/Art%20Miami.png",
+ "site_url": "https://www.artsy.net/art-miami-2018"
},
{
- "logo_url": "https://d3vpvtm3t56z1n.cloudfront.net/images/designmiami.jpg",
- "site_url": ""
+ "logo_url": "https://artsy-media-uploads.s3.amazonaws.com/NAsbMWiP_RGE9sxHDxUSxw/CONTEXT%20Miami.png",
+ "site_url": "https://www.artsy.net/context-art-miami-2018"
},
{
- "logo_url": "https://d3vpvtm3t56z1n.cloudfront.net/images/ink.jpg",
- "site_url": ""
+ "logo_url": "https://artsy-media-uploads.s3.amazonaws.com/_MmDstUwULPLvMm4U8DiaQ/Aqua%20Miami.png",
+ "site_url": "https://www.artsy.net/aqua-art-miami-2018"
},
{
- "logo_url": "https://d3vpvtm3t56z1n.cloudfront.net/images/artmiami.jpg",
- "site_url": ""
+ "logo_url": "https://artsy-media-uploads.s3.amazonaws.com/wzRMCWRdWY-grjY8dRARmw/PULSE%20Miami%20Beach.png",
+ "site_url": "https://www.artsy.net/pulse-miami-beach-2018"
},
{
- "logo_url": "https://d3vpvtm3t56z1n.cloudfront.net/images/context.jpg",
- "site_url": ""
+ "logo_url": "http://files.artsy.net/images/untitled.png",
+ "site_url": "https://www.artsy.net/untitled-art-miami-beach-2018"
},
{
- "logo_url": "https://d3vpvtm3t56z1n.cloudfront.net/images/aqua.jpg",
- "site_url": ""
+ "logo_url": "http://files.artsy.net/images/nadamiami.png",
+ "site_url": "https://www.artsy.net/nada-miami-2018"
},
{
- "logo_url": "https://d3vpvtm3t56z1n.cloudfront.net/images/pulse.jpg",
- "site_url": ""
+ "logo_url": "http://files.artsy.net/images/scopemiami.png",
+ "site_url": "https://www.artsy.net/scope-miami-beach-2018"
}
]
},
"artsy_in_miami": {
- "title": "Artsy in Miami",
- "banner_image_url": "https://d3vpvtm3t56z1n.cloudfront.net/images/artsyinmiami.jpg",
- "description": "Collective Structures explores the relationship between individual artists and their mental landscape through a series of spatial installations. It will unfold in multiple chapters, across distinct spaces of the Bath Club, drawing on the historic building. The physical and sensory experiences strive to place viewers at a crossroads between current reality and imagined narrative.",
- "public_viewing_date": "Public Viewing
December 7 12:00pm–6:00pm
The Bath Club
5937 Collins Ave, Miami Beach"
+ "title": null,
+ "banner_image_url": null,
+ "description": null,
+ "public_viewing_date": null
},
"prepare_for_fairs": {
- "title": "Stories from Miami",
+ "title": "Preparing for the fairs",
"articles": [
{
- "image_url": "https://d7hftxdivxxvm.cloudfront.net/?resize_to=width&src=https%3A%2F%2Fartsy-media-uploads.s3.amazonaws.com%2FlhQti2pXrsXDLlS8jJEIDg%252F_AR_3443.jpg&width=1100&quality=80",
- "title": "The 20 Best Booths at Art Basel in Miami Beach",
- "author": "ANNA LOUIE SUSSMAN",
- "article_url": "https://www.artsy.net/article/artsy-editorial-the-20-best-booths-at-art-basel-in-miami-beach"
+ "article_url": "https://www.artsy.net/article/artsy-specialist-3-reasons-buy-art-fairs",
+ "author": "ARTSY SPECIALIST",
+ "image_url": "https://artsy-media-uploads.s3.amazonaws.com/6CJOf-XW90R0ML3xfUfwRQ/3reasons.jpg",
+ "title": "3 Reasons to Buy Art at Art Fairs"
},
{
- "image_url": "https://d7hftxdivxxvm.cloudfront.net/?resize_to=width&src=https%3A%2F%2Fartsy-media-uploads.s3.amazonaws.com%2FvClMRePyeu9nCashzAgEeA%252F_AR_3326.jpg&width=1100&quality=80",
- "title": "50 Must-See Artworks at Miami Art Week’s Satellite Fairs",
- "author": "ARTSY EDITORIAL",
- "article_url": "https://www.artsy.net/article/artsy-editorial-50-must-see-artworks-at-miami-art-week-s-satellite-fairs"
+ "article_url": "https://www.artsy.net/article/artsy-specialist-best-deal-art-fair",
+ "author": "ARTSY SPECIALIST",
+ "image_url": "https://artsy-media-uploads.s3.amazonaws.com/4EiO7x1TI7adea0PsfYKvw/bestdeal.jpg",
+ "title": " How to Get the Best Deal at an Art Fair"
},
{
- "image_url": "https://d7hftxdivxxvm.cloudfront.net/?resize_to=width&src=https%3A%2F%2Fartsy-media-uploads.s3.amazonaws.com%2FOX8QZ5TCXVt8szczr7oWZQ%252Fammann.jpg&width=1100&quality=80",
- "title": "The 10 Best Booths at Design Miami/",
- "author": "ARTSY EDITORIAL",
- "article_url": "https://www.artsy.net/article/artsy-editorial-the-10-best-booths-at-design-miami"
+ "article_url": "https://www.artsy.net/article/artsy-specialist-prepare-first-art-fair",
+ "author": "ARTSY SPECIALIST",
+ "image_url": "https://artsy-media-uploads.s3.amazonaws.com/UN_o-HYwLY0Y4M7zlgdoVQ/prepareforfairs.jpg",
+ "title": "How to Prepare for Your First Art Fair"
}
]
}
-}
+}
\ No newline at end of file
diff --git a/src/desktop/apps/artsy_in_miami/templates/meta.jade b/src/desktop/apps/artsy_in_miami/templates/meta.jade
index 536e9fc48bb..1448bc7ae77 100644
--- a/src/desktop/apps/artsy_in_miami/templates/meta.jade
+++ b/src/desktop/apps/artsy_in_miami/templates/meta.jade
@@ -1,8 +1,5 @@
-- var title = 'Art Basel and more on Artsy | Miami Week 2017'
-- var description = 'Artsy is your guide to Miami Week 2017. Explore the fairs, editorial coverage, Artsy events, and more—all in one place. December 4-10.'
-
-title= title
-meta( property="og:title", content=title )
-meta( name="description", content=description )
-meta( name="og:description", content=description )
-meta( property="twitter:description", content=description )
\ No newline at end of file
+title= data.meta.title
+meta( property="og:title", content=data.meta.title )
+meta( name="description", content=data.meta.description )
+meta( name="og:description", content=data.meta.description )
+meta( property="twitter:description", content=data.meta.description )
\ No newline at end of file
diff --git a/src/desktop/apps/artwork/client/bootstrap.coffee b/src/desktop/apps/artwork/client/bootstrap.coffee
index 1b1cb5fe096..d82fa789362 100644
--- a/src/desktop/apps/artwork/client/bootstrap.coffee
+++ b/src/desktop/apps/artwork/client/bootstrap.coffee
@@ -5,3 +5,6 @@ module.exports = (sd, { artwork }) ->
context: artwork.context
href: artwork.href
artists: artwork.artists
+ pageviews: artwork.pageviews
+ is_acquireable: artwork.is_acquireable
+ is_offerable: artwork.is_offerable
\ No newline at end of file
diff --git a/src/desktop/apps/artwork/client/index.coffee b/src/desktop/apps/artwork/client/index.coffee
index 97f9e92a1fe..c25746e2c87 100644
--- a/src/desktop/apps/artwork/client/index.coffee
+++ b/src/desktop/apps/artwork/client/index.coffee
@@ -1,5 +1,5 @@
{ extend, map, compact } = require 'underscore'
-{ AUCTION, CLIENT } = require('sharify').data
+{ AUCTION, CLIENT, INTERCOM_BUYER_APP_ID, INTERCOM_BUYER_ENABLED, INTERCOM_BUYER_HASH } = require('sharify').data
{ setCookie } = require '../../../components/recently_viewed_artworks/index.coffee'
{ recordArtworkView } = require '../../../../lib/components/record_artwork_view'
metaphysics = require '../../../../lib/metaphysics.coffee'
@@ -7,6 +7,8 @@ CurrentUser = require '../../../models/current_user.coffee'
exec = require '../lib/exec.coffee'
fold = -> require('./fold.jade') arguments...
footer = -> require('./footer.jade') arguments...
+splitTest = require '../../../components/split_test/index.coffee'
+{ enableIntercom } = require '../../../../lib/intercom'
helpers = extend [
{}
@@ -159,9 +161,13 @@ module.exports =
user: CurrentUser.orNull()
init: ->
+ currentUser = CurrentUser.orNull()
setCookie(CLIENT._id)
- recordArtworkView(CLIENT._id, CurrentUser.orNull())
+ recordArtworkView(CLIENT._id, currentUser)
+ splitTest('artwork_sidebar_pageviews').view() if CLIENT.pageviews?
exec sharedInit
+ enableIntercom(CLIENT)
+
context = CLIENT.context or {}
{ query, init, variables } = setup(context)
diff --git a/src/desktop/apps/artwork/components/auction/templates/index.jade b/src/desktop/apps/artwork/components/auction/templates/index.jade
index 29788e3af61..4ef5b276b3e 100644
--- a/src/desktop/apps/artwork/components/auction/templates/index.jade
+++ b/src/desktop/apps/artwork/components/auction/templates/index.jade
@@ -1,7 +1,5 @@
- var auction = artwork.sale
- var sale_artwork = artwork.sale_artwork
-- var labFeatures = sd && sd.CURRENT_USER && sd.CURRENT_USER.lab_features
-
if auction.is_auction_promo
//- Unimplemented
@@ -11,8 +9,9 @@ else if auction.is_preview || auction.is_open || auction.is_live_open
include ./live
include ./bid
include ./buy_now
- if labFeatures && labFeatures.indexOf("Pageviews in Sidebar") > -1
- != stitch.components.ArtworkSidebarPageviews({artworkID: artwork.id})
+ if sd && sd.stitch.components && sd.ARTWORK_SIDEBAR_PAGEVIEWS === 'experiment'
+ #stitch-pageviews-mountpoint
+ != sd.stitch.components.ArtworkSidebarPageviews({artworkID: artwork.id, mountId: 'stitch-pageviews-mountpoint'})
include ./buyers_premium
include ./help
diff --git a/src/desktop/apps/artwork/components/commercial/templates/index.jade b/src/desktop/apps/artwork/components/commercial/templates/index.jade
index 60518f8e5e8..52f97ddb328 100644
--- a/src/desktop/apps/artwork/components/commercial/templates/index.jade
+++ b/src/desktop/apps/artwork/components/commercial/templates/index.jade
@@ -1,7 +1,6 @@
- var auctionPartner = artwork.partner.type === 'Auction' || artwork.partner.type === 'Auction House'
-- var labFeatures = sd.CURRENT_USER && sd.CURRENT_USER.lab_features
- var isCommercial = artwork.is_acquireable || artwork.is_offerable || artwork.is_inquireable
-- var hasLabFeature = labFeatures && labFeatures.indexOf("Pageviews in Sidebar") > -1
+- var hasPageviewFeature = sd.ARTWORK_SIDEBAR_PAGEVIEWS === 'experiment'
.artwork-commercial( class='js-artwork-commercial' )
form.artwork-commercial__form
@@ -13,7 +12,7 @@
else if artwork.is_inquireable
include inquire
- if isCommercial && hasLabFeature
+ if isCommercial && hasPageviewFeature
!= stitch.components.ArtworkSidebarPageviews({artworkID: artwork.id})
include partner
diff --git a/src/desktop/apps/artwork/components/commercial/templates/price.jade b/src/desktop/apps/artwork/components/commercial/templates/price.jade
index 3ba2adb8c8c..4a080f1541e 100644
--- a/src/desktop/apps/artwork/components/commercial/templates/price.jade
+++ b/src/desktop/apps/artwork/components/commercial/templates/price.jade
@@ -10,11 +10,12 @@ if artwork.sale_message || isPermanentCollection
if artwork.is_price_range
.tooltip-question-container
!= stitch.components.TooltipQuestion({horizontalAlign: 'left', message: 'The range is an approximate indication of the work’s price point, and the exact price is quoted upon request.'})
- .artwork-commercial__shipping-info
- | #{artwork.shippingInfo}
- if artwork.shippingOrigin
- br
- | Ships from #{artwork.shippingOrigin}
+ if artwork.is_acquireable || artwork.is_offerable
+ .artwork-commercial__shipping-info
+ | #{artwork.shippingInfo}
+ if artwork.shippingOrigin
+ br
+ | Ships from #{artwork.shippingOrigin}
else if isPermanentCollection
| Permanent collection
else
diff --git a/src/desktop/apps/artwork/components/commercial/test/template.coffee b/src/desktop/apps/artwork/components/commercial/test/template.coffee
index be936629339..b43ce1f3167 100644
--- a/src/desktop/apps/artwork/components/commercial/test/template.coffee
+++ b/src/desktop/apps/artwork/components/commercial/test/template.coffee
@@ -108,3 +108,23 @@ describe 'Commercial template', ->
is_for_sale: true
$ = cheerio.load html
$('.js-artwork-bnmo-ask-specialist').length.should.eql 0
+
+ it 'shows shipping information for ecommerce artworks', ->
+ html = renderArtwork
+ artwork: acquireableArtwork
+ artworkOptions:
+ price: '$5,000'
+ shippingInfo: "Shipping: $50 continental US, $100 rest of world"
+ shippingOrigin: "New York, New York, US"
+ $ = cheerio.load html
+ $('.artwork-commercial__shipping-info').length.should.eql 1
+
+ it 'does not show shipping information when unenrolled from ecommerce programs', ->
+ html = renderArtwork
+ artwork: inquireableArtwork
+ artworkOptions:
+ price: '$5,000'
+ shippingInfo: "Shipping: $50 continental US, $100 rest of world"
+ shippingOrigin: "New York, New York, US"
+ $ = cheerio.load html
+ $('.artwork-commercial__shipping-info').length.should.eql 0
diff --git a/src/desktop/apps/artwork/components/metadata/query.coffee b/src/desktop/apps/artwork/components/metadata/query.coffee
index f2f8101934c..ea4cc797dd4 100644
--- a/src/desktop/apps/artwork/components/metadata/query.coffee
+++ b/src/desktop/apps/artwork/components/metadata/query.coffee
@@ -29,5 +29,6 @@ module.exports = """
sale_artwork {
lot_label
}
+ pageviews
}
"""
diff --git a/src/desktop/apps/artwork2/client.js b/src/desktop/apps/artwork2/client.js
deleted file mode 100644
index edef302bc78..00000000000
--- a/src/desktop/apps/artwork2/client.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import { buildClientApp } from "reaction/Artsy/Router/client"
-import { routes } from "reaction/Apps/Artwork/routes"
-import React from "react"
-import ReactDOM from "react-dom"
-
-buildClientApp({ routes })
- .then(({ ClientApp }) => {
- ReactDOM.hydrate(, document.getElementById("react-root"))
- })
- .catch(error => {
- console.error(error)
- })
-
-if (module.hot) {
- module.hot.accept()
-}
diff --git a/src/desktop/apps/artwork2/client.tsx b/src/desktop/apps/artwork2/client.tsx
new file mode 100644
index 00000000000..773178013a9
--- /dev/null
+++ b/src/desktop/apps/artwork2/client.tsx
@@ -0,0 +1,90 @@
+import { buildClientApp } from "reaction/Artsy/Router/client"
+import { routes } from "reaction/Apps/Artwork/routes"
+import { data as sd } from "sharify"
+import React from "react"
+import ReactDOM from "react-dom"
+import styled from "styled-components"
+
+const mediator = require("desktop/lib/mediator.coffee")
+const User = require("desktop/models/user.coffee")
+const Artwork = require("desktop/models/artwork.coffee")
+const ArtworkInquiry = require("desktop/models/artwork_inquiry.coffee")
+const openInquiryQuestionnaireFor = require("desktop/components/inquiry_questionnaire/index.coffee")
+const openAuctionBuyerPremium = require("desktop/apps/artwork/components/auction/components/buyers_premium/index.coffee")
+
+// FIXME: Move this to Reaction
+const Container = styled.div`
+ width: 100%;
+ max-width: 1192px;
+ margin: auto;
+`
+
+buildClientApp({
+ routes,
+ context: {
+ user: sd.CURRENT_USER,
+ mediator,
+ },
+})
+ .then(({ ClientApp }) => {
+ ReactDOM.hydrate(
+
+
+ ,
+ document.getElementById("react-root")
+ )
+ })
+ .catch(error => {
+ console.error(error)
+ })
+
+if (module.hot) {
+ module.hot.accept()
+}
+
+const openInquireableModal = (artworkId: string, { ask_specialist }) => {
+ if (!artworkId) return
+ const user = User.instantiate()
+ const inquiry = new ArtworkInquiry({ notification_delay: 600 })
+ const artwork = new Artwork({ id: artworkId })
+
+ artwork.fetch().then(() => {
+ openInquiryQuestionnaireFor({
+ user,
+ artwork,
+ inquiry,
+ ask_specialist,
+ })
+ })
+}
+
+mediator.on("launchInquiryFlow", options => {
+ openInquireableModal(options.artworkId, { ask_specialist: false })
+})
+
+mediator.on("openBuyNowAskSpecialistModal", options => {
+ openInquireableModal(options.artworkId, { ask_specialist: true })
+})
+
+mediator.on("openAuctionAskSpecialistModal", options => {
+ const artworkId = options.artworkId
+ if (artworkId) {
+ const user = User.instantiate()
+ const inquiry = new ArtworkInquiry({ notification_delay: 600 })
+ const artwork = new Artwork({ id: artworkId })
+
+ artwork.fetch().then(() => {
+ artwork.set("is_in_auction", true)
+ openInquiryQuestionnaireFor({
+ user,
+ artwork,
+ inquiry,
+ ask_specialist: true,
+ })
+ })
+ }
+})
+
+mediator.on("openAuctionBuyerPremium", options => {
+ openAuctionBuyerPremium(options.auctionId)
+})
diff --git a/src/desktop/apps/artwork2/server.js b/src/desktop/apps/artwork2/server.js
deleted file mode 100644
index 74c5e6ef0e5..00000000000
--- a/src/desktop/apps/artwork2/server.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import express from "express"
-import adminOnly from "desktop/lib/admin_only"
-import { buildServerApp } from "reaction/Artsy/Router/server"
-import { routes } from "reaction/Apps/Artwork/routes"
-import { stitch } from "@artsy/stitch"
-import { Meta } from "./components/Meta"
-import { buildServerAppContext } from "desktop/lib/buildServerAppContext"
-
-const app = (module.exports = express())
-
-app.get("/artwork2/:artworkID*", adminOnly, async (req, res, next) => {
- try {
- const { ServerApp, redirect, status } = await buildServerApp({
- routes,
- url: req.url,
- context: buildServerAppContext(req, res),
- })
-
- if (redirect) {
- res.redirect(302, redirect.url)
- return
- }
-
- const layout = await stitch({
- basePath: __dirname,
- layout: "../../components/main_layout/templates/react_redesign.jade",
- config: {
- styledComponents: true,
- },
- blocks: {
- head: Meta,
- body: ServerApp,
- },
- locals: {
- ...res.locals,
- assetPackage: "artwork2",
- styledComponents: true,
- },
- })
-
- res.status(status).send(layout)
- } catch (error) {
- console.log(error)
- next(error)
- }
-})
-
-export default app
diff --git a/src/desktop/apps/artwork2/server.tsx b/src/desktop/apps/artwork2/server.tsx
new file mode 100644
index 00000000000..8d2f04ffcf7
--- /dev/null
+++ b/src/desktop/apps/artwork2/server.tsx
@@ -0,0 +1,75 @@
+import React from "react"
+import adminOnly from "desktop/lib/admin_only"
+import { buildServerApp } from "reaction/Artsy/Router/server"
+import { routes } from "reaction/Apps/Artwork/routes"
+import { stitch } from "@artsy/stitch"
+import { Meta } from "./components/Meta"
+import { buildServerAppContext } from "desktop/lib/buildServerAppContext"
+import styled from "styled-components"
+import express, { Request, Response, NextFunction } from "express"
+
+export const app = express()
+
+app.get(
+ "/artwork2/:artworkID*",
+ adminOnly,
+ async (req: Request, res: Response, next: NextFunction) => {
+ try {
+ const {
+ ServerApp,
+ redirect,
+ status,
+ headTags,
+ scripts,
+ } = await buildServerApp({
+ routes,
+ url: req.url,
+ userAgent: req.header("User-Agent"),
+ context: buildServerAppContext(req, res),
+ })
+
+ if (redirect) {
+ res.redirect(302, redirect.url)
+ return
+ }
+
+ // FIXME: Move this to Reaction
+ const Container = styled.div`
+ width: 100%;
+ max-width: 1192px;
+ margin: auto;
+ `
+
+ const layout = await stitch({
+ basePath: __dirname,
+ layout: "../../components/main_layout/templates/react_redesign.jade",
+ config: {
+ styledComponents: true,
+ },
+ blocks: {
+ head: () => (
+
+ {headTags}
+
+
+ ),
+ body: () => (
+
+
+
+ ),
+ },
+ locals: {
+ ...res.locals,
+ assetPackage: "artwork2",
+ scripts,
+ },
+ })
+
+ res.status(status).send(layout)
+ } catch (error) {
+ console.log(error)
+ next(error)
+ }
+ }
+)
diff --git a/src/desktop/apps/auction_support/client/registration_form.coffee b/src/desktop/apps/auction_support/client/registration_form.coffee
index 8e699c4138a..c620f721937 100644
--- a/src/desktop/apps/auction_support/client/registration_form.coffee
+++ b/src/desktop/apps/auction_support/client/registration_form.coffee
@@ -27,6 +27,7 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
@$conditionsCheckbox = @$('.artsy-checkbox')
@$submit = @$('.registration-form-content .avant-garde-button-black')
@setUpFields()
+ @setUpStripe()
showBiddingDialog: (e) ->
e.preventDefault()
@@ -37,27 +38,36 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
setUpFields: ->
@fields =
'name on card': { el: @$('input[name=card_name]'), validator: @isPresent }
- 'card number': { el: @$('input[name=card_number]'), validator: @isCardNumber }
- 'security code': { el: @$('input[name=card_security_code]'), validator: @isPresent }
telephone: { el: @$('input.telephone'), validator: @isPresent }
- month: { el: @$('.card-expiration .month select'), validator: @isPresent }
- year: { el: @$('.card-expiration .year select'), validator: @isPresent }
street: { el: @$('input.street'), validator: @isPresent, label: 'address' }
city: { el: @$('input.city'), validator: @isPresent, label: 'city' }
state: { el: @$('input.region'), validator: @isState, label: 'state' }
zip: { el: @$('input.postal-code'), validator: @isZip }
@internationalizeFields()
+ setUpStripe: ->
+ @stripe = Stripe(STRIPE_PUBLISHABLE_KEY)
+ elements = @stripe.elements()
+ @card = elements.create('card', {
+ style: {
+ base: {
+ fontFamily: '"Adobe Garamond W08", Georgia, Serif',
+ fontSize: '16px',
+ '::placeholder': {
+ color: '#cccccc',
+ },
+ }
+ }
+ })
+ @card.update({ hidePostalCode: true })
+ @card.mount('#card-element')
+
disableForm: ->
@$('.auction-registration-form input, .auction-registration-form select').attr('disabled', true)
@undelegateEvents()
cardData: ->
name: @fields['name on card'].el.val()
- number: @fields['card number'].el.val()
- exp_month: @fields.month.el.first().val()
- exp_year: @fields.year.el.last().val()
- cvc: @fields['security code'].el.val()
address_line1: @fields.street.el.val()
address_city: @fields.city.el.val()
address_state: @fields.state.el.val()
@@ -67,12 +77,12 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
tokenizeCard: ->
Q.Promise (resolve, reject) =>
# Attempt to tokenize the credit card through Stripe
- Stripe.setPublishableKey STRIPE_PUBLISHABLE_KEY
- Stripe.card.createToken @cardData(), (status, data) ->
- if status is 200
- resolve data
+ @stripe.createToken(@card, @cardData()).then (result) ->
+ if result.token
+ resolve result
else
- reject data.error.message
+ reject result.error.message
+
.then (data) =>
analyticsHooks.trigger 'registration:validated'
@@ -80,7 +90,7 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
Q.Promise (resolve, reject) =>
card = new Backbone.Model
card.url = "#{API_URL}/api/v1/me/credit_cards"
- card.save { token: data.id, provider: 'stripe' },
+ card.save { token: data.token.id, provider: 'stripe' },
success: (creditCard) =>
if creditCard.get("address_zip_check") == "fail"
reject @errors.badZip
@@ -88,7 +98,8 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
reject @errors.badSecurityCode
else
resolve(creditCard)
- error: (m, xhr) -> reject(xhr.responseJSON?.message)
+ error: (m, xhr) ->
+ reject(xhr.responseJSON?.message)
.then =>
# Create the "bidder" model for the user in this sale
Q.Promise (resolve, reject) =>
diff --git a/src/desktop/apps/auction_support/templates/bid-form.jade b/src/desktop/apps/auction_support/templates/bid-form.jade
index b1848bea7fa..ae315757acd 100644
--- a/src/desktop/apps/auction_support/templates/bid-form.jade
+++ b/src/desktop/apps/auction_support/templates/bid-form.jade
@@ -2,7 +2,7 @@ extends ../../../components/main_layout/templates/minimal_header
append locals
- assetPackage = 'auctions'
- - options = {stripe: true}
+ - options = {stripev3: true}
block body
#auction-registration-page
@@ -46,7 +46,7 @@ block body
else
include ./conditions-of-sale-checkbox.jade
.auction-bid-form-confirm.avant-garde-button-black.is-block.is-disabled Confirm Bid
-
+
else
.bid-section-header= sd.BIDDER_H1_COPY
p.note= sd.BIDDER_H2_COPY
diff --git a/src/desktop/apps/auction_support/templates/registration.jade b/src/desktop/apps/auction_support/templates/registration.jade
index b07f9e20d88..c84800edbff 100644
--- a/src/desktop/apps/auction_support/templates/registration.jade
+++ b/src/desktop/apps/auction_support/templates/registration.jade
@@ -2,7 +2,7 @@ extends ../../../components/main_layout/templates/minimal_header
append locals
- assetPackage = 'auctions'
- - options = {stripe: true}
+ - options = {stripev3: true}
block body
#auction-registration-page
diff --git a/src/desktop/apps/auction_support/test/client/registration_form.coffee b/src/desktop/apps/auction_support/test/client/registration_form.coffee
index c2f92cda8f5..4723ad20749 100644
--- a/src/desktop/apps/auction_support/test/client/registration_form.coffee
+++ b/src/desktop/apps/auction_support/test/client/registration_form.coffee
@@ -10,15 +10,20 @@ RegistrationForm = require '../../client/registration_form'
DateHelpers = require '../../../../components/util/date_helpers.coffee'
describe 'RegistrationForm', ->
-
before (done) ->
benv.setup =>
benv.expose
$: benv.require('jquery'),
Stripe: @Stripe =
- setPublishableKey: sinon.stub()
- card:
- createToken: sinon.stub().yields(200, {})
+ sinon.stub().returns({
+ createToken: sinon.stub().returns(Promise.resolve({ token: { id: '123' } }))
+ elements: sinon.stub().returns({
+ create: sinon.stub().returns({
+ update: sinon.stub()
+ mount: sinon.stub()
+ })
+ })
+ })
Backbone.$ = $
done()
@@ -53,10 +58,6 @@ describe 'RegistrationForm', ->
@acceptConditions = => @view.$acceptConditions.prop('checked', true)
@submitValidForm = =>
@view.$('input[name="card_name"]').val 'Foo Bar'
- @view.$('select[name="card_expiration_month"]').val '1'
- @view.$('select[name="card_expiration_year"]').val '2024'
- @view.$('input[name="card_number"]').val '4111111111111111'
- @view.$('input[name="card_security_code"]').val '123'
@view.$('input[name="address[street]"]').val '456 Foo Bar Ln.'
@view.$('input[name="address[city]"]').val 'Foobarrington'
@view.$('input[name="address[region]"]').val 'FB'
@@ -79,14 +80,14 @@ describe 'RegistrationForm', ->
done()
it 'validates the form and displays errors', ->
+ @acceptConditions()
+
@view.$submit.length.should.be.ok()
@view.$submit.click()
@view.once 'submitted', =>
html = @view.$el.html()
html.should.containEql 'Invalid name on card'
- html.should.containEql 'Invalid card number'
- html.should.containEql 'Invalid security code'
html.should.containEql 'Invalid city'
html.should.containEql 'Invalid state'
html.should.containEql 'Invalid zip'
@@ -95,33 +96,29 @@ describe 'RegistrationForm', ->
@view.$submit.hasClass('is-loading').should.be.false()
it 'lets the user resubmit a corrected form', ->
- # Submit a bad form
+ @acceptConditions()
+ # Submit a bad form
@view.$submit.length.should.be.ok()
@view.$submit.click()
+
@view.once "submitted", =>
html = @view.$el.html()
html.should.containEql 'Please review the error(s) above and try again.'
- # Now submit a good one
-
- # Successfully create a stripe token
- @Stripe.card.createToken.callsArgWith(1, 200, {})
- # Successfully save phone number
- Backbone.sync.onFirstCall().yieldsTo('success')
- # Successfully save credit card
- Backbone.sync.onSecondCall().yieldsTo('success')
- # Successfully create the bidder
- Backbone.sync.onThirdCall().yieldsTo('success')
-
+ Backbone.sync
+ .yieldsTo 'success', {} # savePhoneNumber success
+ .onCall 1
+ .yieldsTo 'success', { get: () -> 'pass' } # credit card save passes
+ .onCall 2
+ .yieldsTo 'success', {}
- @acceptConditions()
+ # Now submit a good one
@submitValidForm()
- @view.once "submitted", =>
- @Stripe.card.createToken.args[0][1](200, {})
+ @view.once "submitted", =>
# Saves the phone number
- Backbone.sync.args[0][1].changed.phone.should.equal '555-555-5555'
+ Backbone.sync.args[0][2].attrs.phone.should.equal '555-555-5555'
# Saves the credit card
Backbone.sync.args[1][1].url.should.containEql '/api/v1/me/credit_cards'
diff --git a/src/desktop/apps/collect2/meta.tsx b/src/desktop/apps/collect2/meta.tsx
index 0640dd6e737..0a4caec03af 100644
--- a/src/desktop/apps/collect2/meta.tsx
+++ b/src/desktop/apps/collect2/meta.tsx
@@ -2,7 +2,7 @@ import React, { Fragment } from "react"
interface Props {
appUrl: string
- headTags: JSX.Element
+ headTags: JSX.Element[]
}
export const Meta = (props: Props) => {
diff --git a/src/desktop/apps/collect2/server.js b/src/desktop/apps/collect2/server.tsx
similarity index 87%
rename from src/desktop/apps/collect2/server.js
rename to src/desktop/apps/collect2/server.tsx
index ece2d44ac2b..201c0fea9e5 100644
--- a/src/desktop/apps/collect2/server.js
+++ b/src/desktop/apps/collect2/server.tsx
@@ -6,16 +6,16 @@ import React from "react"
import { Meta } from "./meta"
import { buildServerAppContext } from "desktop/lib/buildServerAppContext"
-const app = (module.exports = express())
+export const app = express()
const index = async (req, res, next) => {
try {
- const user = req.user && req.user.toJSON()
const { APP_URL, IS_MOBILE } = res.locals.sd
- const { headTags, ServerApp, redirect } = await buildServerApp({
+ const { headTags, ServerApp, redirect, scripts } = await buildServerApp({
routes,
url: req.url,
+ userAgent: req.header("User-Agent"),
context: buildServerAppContext(req, res),
})
@@ -39,6 +39,7 @@ const index = async (req, res, next) => {
...res.locals,
assetPackage: "collect2",
bodyClass: IS_MOBILE ? "body-header-fixed body-no-margins" : null,
+ scripts,
},
})
@@ -52,5 +53,3 @@ const index = async (req, res, next) => {
app.get("/collect", index)
app.get("/collect/:medium?", index)
app.get("/collection/:slug", index)
-
-export default app
diff --git a/src/desktop/apps/collections/server.js b/src/desktop/apps/collections/server.tsx
similarity index 78%
rename from src/desktop/apps/collections/server.js
rename to src/desktop/apps/collections/server.tsx
index 747212eec8d..16fa3497920 100644
--- a/src/desktop/apps/collections/server.js
+++ b/src/desktop/apps/collections/server.tsx
@@ -1,19 +1,20 @@
+import React from "react"
import { buildServerApp } from "reaction/Artsy/Router/server"
import { stitch } from "@artsy/stitch"
import { routes } from "reaction/Apps/Collections/routes"
import express from "express"
import { buildServerAppContext } from "desktop/lib/buildServerAppContext"
-import adminOnly from "desktop/lib/admin_only"
-const app = (module.exports = express())
+export const app = express()
-app.get("/collections", adminOnly, async (req, res, next) => {
+app.get("/collections", async (req, res, next) => {
try {
const { IS_MOBILE } = res.locals.sd
- const { ServerApp, redirect } = await buildServerApp({
+ const { ServerApp, headTags, redirect, scripts } = await buildServerApp({
routes,
url: req.url,
+ userAgent: req.header("User-Agent"),
context: buildServerAppContext(req, res),
})
@@ -30,13 +31,14 @@ app.get("/collections", adminOnly, async (req, res, next) => {
styledComponents: true,
},
blocks: {
- head: () => null,
+ head: () => <>{headTags}>,
body: ServerApp,
},
locals: {
...res.locals,
assetPackage: "collections",
bodyClass: IS_MOBILE ? "body-header-fixed body-no-margins" : null,
+ scripts,
},
})
@@ -46,5 +48,3 @@ app.get("/collections", adminOnly, async (req, res, next) => {
next(error)
}
})
-
-export default app
diff --git a/src/desktop/apps/fairs/helpers/view_helpers.coffee b/src/desktop/apps/fairs/helpers/view_helpers.coffee
index eebc1897447..f12b10f9c35 100644
--- a/src/desktop/apps/fairs/helpers/view_helpers.coffee
+++ b/src/desktop/apps/fairs/helpers/view_helpers.coffee
@@ -1,5 +1,6 @@
DateHelpers = require '../../../components/util/date_helpers.coffee'
_ = require 'underscore'
+moment = require 'moment'
module.exports =
@@ -52,13 +53,15 @@ module.exports =
fair.is_published and fair.profile?.is_published and fair.profile?.icon?.url
isNotOver: (fair) ->
- Date.parse(fair.end_at) > new Date
+ not @isOver(fair)
isPast: (fair) ->
@isEligible(fair) and @isOver(fair)
isOver: (fair) ->
- Date.parse(fair.end_at) < new Date
+ endOfFair = moment.utc(fair.end_at).endOf("day")
+ now = moment()
+ now.isAfter(endOfFair)
isUpcoming: (fair) ->
@isEventuallyEligible(fair) and @isNotOver(fair)
diff --git a/src/desktop/apps/fairs/test/routes.coffee b/src/desktop/apps/fairs/test/routes.coffee
index 9598d99d051..bb77350efcf 100644
--- a/src/desktop/apps/fairs/test/routes.coffee
+++ b/src/desktop/apps/fairs/test/routes.coffee
@@ -12,15 +12,12 @@ describe 'Fairs routes', ->
image = { url: "https://www.example.com/cat.jpg" }
profile = { is_published: true, icon: { url: "https://www.example.com/cat.jpg" } }
@currentFairs = _.times 2, ->
- fabricate('fair', image: image, profile: profile, id: _.uniqueId(), is_published: true, has_full_feature: true, has_listing: true, organizer: fabricate('fair_organizer'), end_at: moment().add(10, 'days').format(), banner_size: 'x-large')
+ fabricate('fair', image: image, profile: profile, id: _.uniqueId(), is_published: true, has_full_feature: true, has_listing: true, organizer: fabricate('fair_organizer'), start_at: moment().subtract(1, 'days'), end_at: moment().add(11, 'days').format(), banner_size: 'x-large')
@pastFairs = _.times 4, ->
- fabricate('fair', image: image, profile: profile, id: _.uniqueId('past'), is_published: true, has_full_feature: true, has_listing: true, organizer: fabricate('fair_organizer'), end_at: moment().subtract(10, 'days').format())
+ fabricate('fair', image: image, profile: profile, id: _.uniqueId('past'), is_published: true, has_full_feature: true, has_listing: true, organizer: fabricate('fair_organizer'), end_at: moment().subtract(11, 'days').format())
@upcomingFairs = _.times 3, ->
- fabricate('fair', id: _.uniqueId('upcoming'), is_published: true, has_full_feature: true, has_listing: true, organizer: null, end_at: moment().add(10, 'days'))
- @invalidFairs = [
- fabricate('fair', id: _.uniqueId('invalid'), is_published: false)
- fabricate('fair', id: _.uniqueId('invalid'), is_published: true, has_full_feature: false, has_listing: false)
- ]
+ fabricate('fair', id: _.uniqueId('upcoming'), is_published: true, has_full_feature: true, has_listing: true, organizer: null, end_at: moment().add(11, 'days'), start_at: moment().add(1, 'days'))
+
@rows = ViewHelpers.fillRows @currentFairs
@@ -37,7 +34,6 @@ describe 'Fairs routes', ->
@currentFairs
@pastFairs
@upcomingFairs
- @invalidFairs
]
routes.__set__ 'metaphysics', => Q.resolve { featured_fairs: [ fairs: {} ], fairs: @fairs }
@@ -54,7 +50,6 @@ describe 'Fairs routes', ->
@fairs = _.flatten [
@pastFairs
@upcomingFairs
- @invalidFairs
]
routes.__set__ 'metaphysics', => Q.resolve { featured_fairs: [ fairs: {} ], fairs: @fairs }
diff --git a/src/desktop/apps/gallery_partnerships/client/index.coffee b/src/desktop/apps/gallery_partnerships/client/index.coffee
index 59d50870f9a..fb53da766b7 100644
--- a/src/desktop/apps/gallery_partnerships/client/index.coffee
+++ b/src/desktop/apps/gallery_partnerships/client/index.coffee
@@ -1,5 +1,5 @@
initCarousel = require '../../../components/merry_go_round/bottom_nav_mgr.coffee'
-sd = require('sharify').data
+{ CURRENT_USER, INTERCOM_SELLER_APP_ID, INTERCOM_SELLER_ENABLED } = require('sharify').data
module.exports.init = ->
if sd.USER_AGENT.match('iphone')
@@ -8,10 +8,11 @@ module.exports.init = ->
$('.gallery-partnerships2__chat__video').hide()
$('.gallery-partnerships2__chat__fallback_image').show()
- isUserAdmin = sd?.CURRENT_USER?.type == 'Admin'
+ isUserAdmin = CURRENT_USER?.type == 'Admin'
- if sd.INTERCOM_ENABLED && sd.INTERCOM_APP_ID && !isUserAdmin
- intercom = require('./intercom')
+ if INTERCOM_SELLER_ENABLED && INTERCOM_SELLER_APP_ID && !isUserAdmin
+ { intercom } = require('../../../../lib/components/intercom/index')
+ intercom(INTERCOM_SELLER_APP_ID)
initCarousel $('.js-partner-stats-slideshow'), { autoPlay: 2500, wrapAround: true, draggable: false }
initCarousel $('.js-partner-testimonials-slideshow'), { autoPlay: 8000, wrapAround: true, prevNextButtons: false }
diff --git a/src/desktop/apps/isomorphic-relay-example/server.js b/src/desktop/apps/isomorphic-relay-example/server.tsx
similarity index 71%
rename from src/desktop/apps/isomorphic-relay-example/server.js
rename to src/desktop/apps/isomorphic-relay-example/server.tsx
index b480737aef7..760fb7e8144 100644
--- a/src/desktop/apps/isomorphic-relay-example/server.js
+++ b/src/desktop/apps/isomorphic-relay-example/server.tsx
@@ -1,3 +1,4 @@
+import React from "react"
import express from "express"
import adminOnly from "desktop/lib/admin_only"
import { buildServerApp } from "reaction/Artsy/Router/server"
@@ -6,13 +7,20 @@ import { stitch } from "@artsy/stitch"
import { Meta } from "./components/Meta"
import { buildServerAppContext } from "desktop/lib/buildServerAppContext"
-const app = (module.exports = express())
+export const app = express()
app.get("/isomorphic-relay-example*", adminOnly, async (req, res, next) => {
try {
- const { ServerApp, redirect, status } = await buildServerApp({
- routes,
+ const {
+ ServerApp,
+ headTags,
+ redirect,
+ status,
+ scripts,
+ } = await buildServerApp({
+ routes: routes as any,
url: req.url,
+ userAgent: req.header("User-Agent"),
context: buildServerAppContext(req, res),
})
@@ -28,13 +36,18 @@ app.get("/isomorphic-relay-example*", adminOnly, async (req, res, next) => {
styledComponents: true,
},
blocks: {
- head: Meta,
+ head: () => (
+
+ {headTags}
+
+
+ ),
body: ServerApp,
},
locals: {
...res.locals,
assetPackage: "relay",
- styledComponents: true,
+ scripts,
},
})
diff --git a/src/desktop/apps/order2/client.js b/src/desktop/apps/order2/client.js
index eb52c3733b1..c5bfd4dba3d 100644
--- a/src/desktop/apps/order2/client.js
+++ b/src/desktop/apps/order2/client.js
@@ -44,11 +44,12 @@ orderCheckoutFlowEvents.map(eventName => {
)
// Reset timers that track time on page since we're tracking each order
// checkout view as a separate page.
- window.desktopPageTimeTrackers.forEach(tracker => {
- // No need to reset the tracker if we're on the same page.
- if (window.location.pathname !== tracker.path)
- tracker.reset(window.location.pathname)
- })
+ typeof window.desktopPageTimeTrackers !== "undefined" &&
+ window.desktopPageTimeTrackers.forEach(tracker => {
+ // No need to reset the tracker if we're on the same page.
+ if (window.location.pathname !== tracker.path)
+ tracker.reset(window.location.pathname)
+ })
})
})
diff --git a/src/desktop/apps/order2/routes.js b/src/desktop/apps/order2/routes.tsx
similarity index 90%
rename from src/desktop/apps/order2/routes.js
rename to src/desktop/apps/order2/routes.tsx
index 7e1abeee56f..ce7b25423fa 100644
--- a/src/desktop/apps/order2/routes.js
+++ b/src/desktop/apps/order2/routes.tsx
@@ -4,7 +4,7 @@ import { buildServerApp } from "reaction/Artsy/Router/server"
import { buildServerAppContext } from "desktop/lib/buildServerAppContext"
import { routes } from "reaction/Apps/Order/routes"
import { stitch } from "@artsy/stitch"
-import metaphysics from "lib/metaphysics.coffee"
+const metaphysics = require("lib/metaphysics.coffee")
export const checkoutFlow = async (req, res, next) => {
if (!res.locals.sd.CURRENT_USER) {
@@ -13,9 +13,16 @@ export const checkoutFlow = async (req, res, next) => {
)
}
try {
- const { ServerApp, redirect, status, headTags } = await buildServerApp({
+ const {
+ ServerApp,
+ redirect,
+ status,
+ headTags,
+ scripts,
+ } = await buildServerApp({
routes,
url: req.url,
+ userAgent: req.header("User-Agent"),
context: buildServerAppContext(req, res),
})
@@ -58,6 +65,7 @@ export const checkoutFlow = async (req, res, next) => {
options: {
stripev3: true,
},
+ scripts,
},
})
diff --git a/src/desktop/assets/artwork2.styl b/src/desktop/assets/artwork2.styl
new file mode 100644
index 00000000000..5f0b0cf4a0c
--- /dev/null
+++ b/src/desktop/assets/artwork2.styl
@@ -0,0 +1,4 @@
+@require '../components/buyers_premium'
+
+.modalize-body
+ padding 30px
\ No newline at end of file
diff --git a/src/desktop/components/credit_card/client/error_handling_form.coffee b/src/desktop/components/credit_card/client/error_handling_form.coffee
index 27f43519c40..1f05850f435 100644
--- a/src/desktop/components/credit_card/client/error_handling_form.coffee
+++ b/src/desktop/components/credit_card/client/error_handling_form.coffee
@@ -15,7 +15,7 @@ module.exports = class ErrorHandlingForm extends Backbone.View
paymentError: "Your payment could not be processed. Please try again or contact support."
badZip: "The ZIP code provided did not match your card number. Please check it again, try another card, or contact support."
badSecurityCode: "The security code provided did not match your card number. Please check it again, try another card, or contact support."
- other: "There was a problem processing your order. Please try another card or contact support."
+ other: "There was a problem processing your request. Please try another card or contact support."
timeout: "Processing your payment took too long. Please try again or contact support."
connection: "Please check your network connectivity and try again."
@@ -35,7 +35,7 @@ module.exports = class ErrorHandlingForm extends Backbone.View
@filterHtml()
@clearErrors()
for own key, val of @fields
- continue unless val.el.is(':visible') && !val.validator(val.el)
+ continue unless val.el && !val.validator(val.el)
errors[key] = val.message || "Invalid #{val.label || key}"
val.el.addClass 'has-error'
val.el.last().after "#{errors[key]}
"
diff --git a/src/desktop/components/credit_card/stylesheets/index.styl b/src/desktop/components/credit_card/stylesheets/index.styl
index 0a2af75d9cc..d293f52ac47 100644
--- a/src/desktop/components/credit_card/stylesheets/index.styl
+++ b/src/desktop/components/credit_card/stylesheets/index.styl
@@ -22,15 +22,12 @@
width 100%
.order-input-section
margin-bottom 12px
- &.region, &.city, &.postal-code, &.card-name, &.card-expiration, &.card-number, &.card-security-code
+ &.region, &.city, &.postal-code, &.card-number
display inline-block
vertical-align top
- &.city, &.card-name, &.card-number, &.card-security-code
+ &.city, &.card-number
width: 49%
margin-right: 3%
- &.card-security-code
- width: 48%
- margin-right: 0%
&.region
width: 23%
margin-right: 2%
@@ -38,21 +35,6 @@
width: 23%
&.email
margin-bottom: 30px
- &.card-expiration
- width: 48%
- .month, .year
- position relative
- height 51px
- display inline-block
- vertical-align top
- width 47%
- .month
- margin-right: 6%
- .error
- position absolute
- top 4px
- bottom 0px
- left 0px
.order-form-button
width: 100%
.order-form-checkbox
@@ -61,6 +43,18 @@
margin-top: 4px
vertical-align: top
+#card-element
+ border 2px solid gray-lighter-color
+ box-sizing border-box
+ width 100%
+ padding 10px
+ transition border-color 0.25s
+ height 44px
+
+#card-element.StripeElement--focus
+ border-color purple-color
+ outline none
+
.not-usa
.order-form .order-input-section
&.region
diff --git a/src/desktop/components/credit_card/templates/credit_card.jade b/src/desktop/components/credit_card/templates/credit_card.jade
index d1ee5cf90fc..e9806071b21 100644
--- a/src/desktop/components/credit_card/templates/credit_card.jade
+++ b/src/desktop/components/credit_card/templates/credit_card.jade
@@ -2,23 +2,6 @@
label( for='card_name' ) Name on Card
input.bordered-input( type='text', name='card_name', value=name, autocomplete='cc-name' )
-.card-expiration.order-input-section
- label( for='card_expiration' ) Expiration
- .month
- select( name='card_expiration_month', autocomplete="cc-exp-month" )
- option( value='' ) Month
- each month in monthRange
- option( value=month )!= month
- .year
- select( name='card_expiration_year', autocomplete="cc-exp-year" )
- option( value='' ) Year
- each year in yearRange
- option( value=year )!= year
-
-.card-number.order-input-section
- label( for='card_number' ) Credit Card Number
- input.bordered-input( type='text', name='card_number', value=number, autocomplete="cc-number", pattern="\d*" )
-
-.card-security-code.order-input-section
- label( for='card_security_code' ) Security Code
- input.bordered-input( type='text', name='card_security_code', value=security_code, autocomplete="cc-csc", pattern="\d*" )
+label Credit Card Number
+.order-input-section
+ #card-element
diff --git a/src/desktop/components/credit_card_2/icons.json b/src/desktop/components/credit_card_2/icons.json
deleted file mode 100644
index 37fbd519b05..00000000000
--- a/src/desktop/components/credit_card_2/icons.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "American Express": "/cc_American-Express.png",
- "Diners Club": "/cc_Diners-Club.png",
- "Discover": "/cc_Discover.png",
- "JCB": "/cc_JCB.png",
- "MasterCard": "/cc_MasterCard.png",
- "Visa": "/cc_Visa.png",
- "Unknown": "/cc_Unknown.png"
-}
diff --git a/src/desktop/components/credit_card_2/index.jade b/src/desktop/components/credit_card_2/index.jade
deleted file mode 100644
index 146b99dc01e..00000000000
--- a/src/desktop/components/credit_card_2/index.jade
+++ /dev/null
@@ -1,13 +0,0 @@
-form.credit-card-form__form.stacked-form
- .form-errors( class='js-form-errors' )
- //- Rendered client-side
-
- include ./templates/credit_card
-
- h3.credit-card-form__form__subheadline
- | Billing Address
-
- include ./templates/billing_address
-
- button.avant-garde-button-white
- | Add Payment
diff --git a/src/desktop/components/credit_card_2/index.styl b/src/desktop/components/credit_card_2/index.styl
deleted file mode 100644
index 33fb4eac8e2..00000000000
--- a/src/desktop/components/credit_card_2/index.styl
+++ /dev/null
@@ -1,47 +0,0 @@
-@require '../grid'
-@require './modal'
-
-.credit-card-bordered-input
- position relative
- display inline-block
-
- &.is-block
- &, & > .bordered-input
- display block
- width 100%
-
- > .bordered-input
- padding-right 30px
-
- > span
- position absolute
- display block
- top 50%
- right 10px
- width 100px
- height 30px
- background-size contain
- background-position center right
- background-repeat no-repeat
- transform translateY(-50%)
- pointer-events none
-
-.credit-card-form
- margin 0 auto
-
- &__form
- //
- &__subheadline
- margin gutter 0
- padding 10px 0
- border-top 1px solid gray-lighter-color
- avant-garde-size('s-headline')
-
-icons = json('./icons.json', { hash: true })
-
-.credit-card-icon
- background-size contain
- background-repeat no-repeat
- for provider, src in icons
- &[data-provider=\'{provider}\']
- background-image url(src)
diff --git a/src/desktop/components/credit_card_2/modal/index.coffee b/src/desktop/components/credit_card_2/modal/index.coffee
deleted file mode 100644
index 61f31936498..00000000000
--- a/src/desktop/components/credit_card_2/modal/index.coffee
+++ /dev/null
@@ -1,14 +0,0 @@
-modalize = require '../../modalize/index.coffee'
-CreditCardView = require './view.coffee'
-
-module.exports = ({ collection } = {}) ->
- view = new CreditCardView collection: collection
-
- modal = modalize view,
- dimensions: width: '800px', height: '800px'
-
- view.once 'abort done', ->
- modal.close()
-
- modal.open()
- modal
diff --git a/src/desktop/components/credit_card_2/modal/index.jade b/src/desktop/components/credit_card_2/modal/index.jade
deleted file mode 100644
index 4a7dc4a5f69..00000000000
--- a/src/desktop/components/credit_card_2/modal/index.jade
+++ /dev/null
@@ -1,20 +0,0 @@
-header.credit-card-modal__header
- h1 Add Credit Card
-
-form.credit-card-modal__form
- .credit-card-modal__form__fields.stacked-form
- .form-errors( class='js-form-errors' )
- //- Rendered client-side
-
- include ../templates/credit_card
-
- h3.credit-card-modal__form__fields__subheadline
- | Billing Address
-
- include ../templates/billing_address
-
- .credit-card-modal__form__buttons
- a.avant-garde-button-white( class='js-cancel' )
- | Cancel
- button.avant-garde-button-black
- | Add
diff --git a/src/desktop/components/credit_card_2/modal/index.styl b/src/desktop/components/credit_card_2/modal/index.styl
deleted file mode 100644
index d3e65d28299..00000000000
--- a/src/desktop/components/credit_card_2/modal/index.styl
+++ /dev/null
@@ -1,60 +0,0 @@
-credit-card-modal = {
- header: {
- height: 70px
- }
-}
-
-.credit-card-modal
- position relative
- height 100%
-
- &__header
- garamond-size('headline')
- position absolute
- top 0
- right 0
- left 0
- height: credit-card-modal.header.height
- line-height @height
- padding 0 gutter
- border-bottom 1px solid gray-lighter-color
-
- &__form
- position absolute
- top: credit-card-modal.header.height
- right 0
- bottom 0
- left 0
-
- &__fields
- position absolute
- margin: 0 0 credit-card-modal.header.height 0
- padding gutter 25%
- top 0
- right 0
- bottom 0
- left 0
- overflow-y auto
- -webkit-overflow-scrolling touch
-
- &__subheadline
- avant-garde-size('s-headline')
- margin gutter 0
- padding 10px 0
- border-top 1px solid gray-lighter-color
-
- &__buttons
- position absolute
- display flex
- justify-content flex-end
- align-items center
- height: credit-card-modal.header.height
- right 0
- bottom 0
- left 0
- padding 0 gutter
- border-top 1px solid gray-lighter-color
-
- > a
- > button
- inline-block-margins(gutter / 4)
diff --git a/src/desktop/components/credit_card_2/modal/view.coffee b/src/desktop/components/credit_card_2/modal/view.coffee
deleted file mode 100644
index 3d53b3b700b..00000000000
--- a/src/desktop/components/credit_card_2/modal/view.coffee
+++ /dev/null
@@ -1,39 +0,0 @@
-{ invoke } = require 'underscore'
-Backbone = require 'backbone'
-CreditCardView = require '../view.coffee'
-template = -> require('./index.jade') arguments...
-
-module.exports = class CreditCardModalView extends Backbone.View
- className: 'credit-card-modal'
-
- events:
- 'click .js-cancel': 'cancel'
-
- initialize: ->
- @listenTo @collection, 'add', @done
-
- done: (model) ->
- model.once 'sync', =>
- @trigger 'done'
-
- cancel: (e) ->
- e.preventDefault()
- @trigger 'abort'
-
- postRender: ->
- creditCardView = new CreditCardView
- el: @$el
- collection: @collection
-
- @subViews = [
- creditCardView
- ]
-
- render: ->
- @$el.html template()
- @postRender()
- this
-
- remove: ->
- invoke @subViews, 'remove'
- super
diff --git a/src/desktop/components/credit_card_2/public/cc_American-Express.png b/src/desktop/components/credit_card_2/public/cc_American-Express.png
deleted file mode 100755
index 27258a4247b..00000000000
Binary files a/src/desktop/components/credit_card_2/public/cc_American-Express.png and /dev/null differ
diff --git a/src/desktop/components/credit_card_2/public/cc_Diners-Club.png b/src/desktop/components/credit_card_2/public/cc_Diners-Club.png
deleted file mode 100755
index d45b27cdaf4..00000000000
Binary files a/src/desktop/components/credit_card_2/public/cc_Diners-Club.png and /dev/null differ
diff --git a/src/desktop/components/credit_card_2/public/cc_Discover.png b/src/desktop/components/credit_card_2/public/cc_Discover.png
deleted file mode 100755
index 800dcffe9d0..00000000000
Binary files a/src/desktop/components/credit_card_2/public/cc_Discover.png and /dev/null differ
diff --git a/src/desktop/components/credit_card_2/public/cc_JCB.png b/src/desktop/components/credit_card_2/public/cc_JCB.png
deleted file mode 100755
index 6c0885e3143..00000000000
Binary files a/src/desktop/components/credit_card_2/public/cc_JCB.png and /dev/null differ
diff --git a/src/desktop/components/credit_card_2/public/cc_MasterCard.png b/src/desktop/components/credit_card_2/public/cc_MasterCard.png
deleted file mode 100755
index f30ea66be96..00000000000
Binary files a/src/desktop/components/credit_card_2/public/cc_MasterCard.png and /dev/null differ
diff --git a/src/desktop/components/credit_card_2/public/cc_Unknown.png b/src/desktop/components/credit_card_2/public/cc_Unknown.png
deleted file mode 100644
index 1664218eea4..00000000000
Binary files a/src/desktop/components/credit_card_2/public/cc_Unknown.png and /dev/null differ
diff --git a/src/desktop/components/credit_card_2/public/cc_Visa.png b/src/desktop/components/credit_card_2/public/cc_Visa.png
deleted file mode 100755
index 7f4df2ce9a9..00000000000
Binary files a/src/desktop/components/credit_card_2/public/cc_Visa.png and /dev/null differ
diff --git a/src/desktop/components/credit_card_2/templates/billing_address.jade b/src/desktop/components/credit_card_2/templates/billing_address.jade
deleted file mode 100644
index 6f45cb535e5..00000000000
--- a/src/desktop/components/credit_card_2/templates/billing_address.jade
+++ /dev/null
@@ -1,44 +0,0 @@
-//- Stripe fields (not Gravity)
-
-input.bordered-input(
- id='address_line1'
- name='address_line1'
- placeholder='Address'
-)
-
-input.bordered-input(
- name='address_line2'
- placeholder='Address (cont.)'
-)
-
-if countries && countries.length
- label.bordered-select
- select( id='address_country', name='address_country' )
- for country in countries
- option( value= country )
- = country
-else
- input.bordered-input(
- id='address_country'
- name='address_country'
- placeholder='Country'
- )
-
-input.bordered-input(
- id='address_city'
- name='address_city'
- placeholder='City'
-)
-
-input.bordered-input(
- id='address_state'
- name='address_state'
- placeholder='State'
-)
-
-.grid-2-up
- .grid-item: input.bordered-input(
- id='address_zip'
- name='address_zip'
- placeholder='Zip'
- )
diff --git a/src/desktop/components/credit_card_2/templates/credit_card.jade b/src/desktop/components/credit_card_2/templates/credit_card.jade
deleted file mode 100644
index 25a4be0e237..00000000000
--- a/src/desktop/components/credit_card_2/templates/credit_card.jade
+++ /dev/null
@@ -1,40 +0,0 @@
-//- Credit card-related fields intentionally lack a name attribute
-//- to prevent sensitive data from being inadvertently
-//- submitted to our servers.
-
-.stacked-form-cell
- .credit-card-bordered-input.is-block
- input.bordered-input(
- id='cc-number'
- class='js-cc-number'
- data-stripe='number'
- placeholder='Credit Card Number'
- autocomplete='cc-number'
- required
- )
- span.credit-card-bordered-input__type.credit-card-icon(
- class='js-cc-type'
- )
-
-.grid-3-up
- .grid-item
- input.bordered-input.is-block(
- id='exp'
- data-stripe='exp'
- placeholder='MM/YYYY'
- required
- )
- .grid-item
- input.bordered-input.is-block(
- id='cvc'
- data-stripe='cvc'
- placeholder='CVC'
- required
- )
-
-input.bordered-input(
- id='name'
- name='name'
- placeholder='Name on Credit Card'
- required
-)
diff --git a/src/desktop/components/credit_card_2/test/view.coffee b/src/desktop/components/credit_card_2/test/view.coffee
deleted file mode 100644
index d11e0bca505..00000000000
--- a/src/desktop/components/credit_card_2/test/view.coffee
+++ /dev/null
@@ -1,85 +0,0 @@
-benv = require 'benv'
-sinon = require 'sinon'
-Backbone = require 'backbone'
-CurrentUser = require '../../../models/current_user'
-CreditCardView = benv.requireWithJadeify require.resolve('../view.coffee'), ['template']
-stripe = CreditCardView.__get__ 'stripe'
-CreditCardView.__set__ 'jQueryPayment', sinon.stub()
-
-describe 'CreditCardView', ->
- before (done) ->
- benv.setup ->
- benv.expose $: benv.require('jquery'), jQuery: benv.require('jquery')
- Backbone.$ = $
- done()
-
- after ->
- benv.teardown()
-
- beforeEach ->
- sinon.stub stripe, 'initialize'
- sinon.stub CreditCardView::, 'postRender'
-
- @user = new CurrentUser id: 'foobar'
- @view = new CreditCardView collection: @user.related().creditCards
-
- afterEach ->
- stripe.initialize.restore()
- @view.postRender.restore()
-
- describe '#render', ->
- it 'renders the template', ->
- html = @view.render().$el.html()
- html.should.containEql 'Credit Card Number'
- html.should.containEql 'Name on Credit Card'
- html.should.containEql 'Add Payment'
-
- describe '#submit', ->
- beforeEach ->
- sinon.stub Backbone, 'sync'
-
- @view.render()
-
- sinon.stub @view, 'validate'
-
- afterEach ->
- Backbone.sync.restore()
- stripe.tokenize.restore()
-
- describe 'successful', ->
- beforeEach ->
- sinon.stub stripe, 'tokenize'
- .returns Promise.resolve id: 'a_token'
-
- it 'submits the form to the server when submitted/clicked', ->
- @view.$('input[data-stripe="number"]')
- .val '666666666666666666'
-
- @view.$('button').click()
-
- @view.__submit__.then =>
- stripe.tokenize.args[0][0].number
- .should.equal '666666666666666666'
-
- Backbone.sync.called
- .should.be.true()
-
- Backbone.sync.args[0][0]
- .should.equal 'create'
-
- Backbone.sync.args[0][1].toJSON()
- .should.eql
- token: 'a_token'
- provider: 'stripe'
-
- describe 'error state', ->
- beforeEach ->
- sinon.stub stripe, 'tokenize'
- .returns Promise.reject 'Stripe error string'
-
- it 'renders any errors', ->
- @view.$('button').click()
-
- @view.__submit__.then =>
- @view.$('.js-form-errors').text()
- .should.equal 'Stripe error string'
diff --git a/src/desktop/components/credit_card_2/view.coffee b/src/desktop/components/credit_card_2/view.coffee
deleted file mode 100644
index c1461751811..00000000000
--- a/src/desktop/components/credit_card_2/view.coffee
+++ /dev/null
@@ -1,80 +0,0 @@
-{ extend } = require 'underscore'
-Backbone = require 'backbone'
-{ Countries } = require 'places'
-Form = require '../form/index.coffee'
-stripe = require '../stripe/index.coffee'
-jQueryPayment = -> require 'jquery.payment'
-template = -> require('./index.jade') arguments...
-
-module.exports = class CreditCardView extends Backbone.View
- className: 'credit-card-form'
-
- events:
- 'input .js-cc-number': 'type'
- 'click button': 'submit'
- 'input input': 'change'
-
- initialize: ->
- stripe.initialize()
- jQueryPayment()
-
- type: (e) ->
- number = $(e.currentTarget).val()
- provider = stripe.cardType number
- (@$type ?= @$('.js-cc-type'))
- .attr 'data-provider', provider
-
- change: ->
- return if @__changed__
-
- @__changed__ = yes
-
- @$('button')
- .removeClass 'avant-garde-button-white'
- .addClass 'avant-garde-button-black'
-
- validate: (sensitive, validator) ->
- stripe.validate(sensitive).map ({ name, value }) ->
- $input = @$("[data-stripe='#{name}']")
- if value
- validator.clearValidity $input
- else
- validator.setValidity $input, stripe.error(name)
-
- submit: (e) ->
- e.preventDefault()
-
- form = new Form $form: $form = @$('form')
-
- sensitive = stripe.serialize $form
- @validate sensitive, form.validator
-
- return unless form.isReady()
-
- form.state 'loading'
-
- data = extend {}, sensitive, form.data()
-
- @__submit__ = stripe.tokenize data
- .then ({ id }) =>
- @collection.create { token: id, provider: 'stripe' },
- success: -> form.state 'default' # `create` returns model, not Promise
-
- .catch (err) ->
- form.error err
-
- postRender: ->
- @$('[data-stripe="number"]')
- .payment 'formatCardNumber'
-
- @$('[data-stripe="exp"]')
- .payment 'formatCardExpiry'
-
- @$('[data-stripe="cvc"]')
- .payment 'formatCardCVC'
-
- render: ->
- @$el.html template
- countries: Countries
- @postRender()
- this
diff --git a/src/desktop/components/json_page/client/editor.coffee b/src/desktop/components/json_page/client/editor.coffee
index 7915305f539..94486bad321 100644
--- a/src/desktop/components/json_page/client/editor.coffee
+++ b/src/desktop/components/json_page/client/editor.coffee
@@ -1,7 +1,12 @@
_ = require 'underscore'
require 'hulk-editor'
require 'jquery-ui'
-require 'blueimp-file-upload'
+
+# FIXME: When running `test/client.coffee` jQuery dep does not resolve. Seems to
+# be issue related to UMD and benv. This dep isn't necessary for test, however.
+if process.env.NODE_ENV != 'test'
+ require 'blueimp-file-upload'
+
require 'jquery.iframe-transport'
GeminiForm = require '../../../components/gemini_form/view.coffee'
diff --git a/src/desktop/components/main_layout/templates/blank.jade b/src/desktop/components/main_layout/templates/blank.jade
index ce1a6598a24..e2ed480e908 100644
--- a/src/desktop/components/main_layout/templates/blank.jade
+++ b/src/desktop/components/main_layout/templates/blank.jade
@@ -1,6 +1,6 @@
block locals
- bodyClass = helpers ? helpers.buildBodyClass(sd) : ''
- - defaultOptions = {modal: true, flash: true, stripe: false, stripev3: false, sailthru: true, marketo: true, quantcast: true}
+ - defaultOptions = {modal: true, flash: true, stripev3: false, sailthru: true, marketo: true, quantcast: false}
- options = options ? Object.assign({}, defaultOptions, options) : defaultOptions
doctype html
diff --git a/src/desktop/components/main_layout/templates/index.jade b/src/desktop/components/main_layout/templates/index.jade
index cdce738e1ec..1fe6ef1270b 100644
--- a/src/desktop/components/main_layout/templates/index.jade
+++ b/src/desktop/components/main_layout/templates/index.jade
@@ -1,7 +1,7 @@
//- Override any locals with `append locals`
block locals
- bodyClass = helpers ? helpers.buildBodyClass(sd, 'body-header-fixed') : '';
- - defaultOptions = {modal: true, flash: true, stripe: false, stripev3: false, sailthru: true, marketo: true, quantcast: true}
+ - defaultOptions = {modal: true, flash: true, stripev3: false, sailthru: true, marketo: true, quantcast: false}
- options = options ? Object.assign({}, defaultOptions, options) : defaultOptions
doctype html
diff --git a/src/desktop/components/main_layout/templates/minimal_header.jade b/src/desktop/components/main_layout/templates/minimal_header.jade
index d82ecb86ed2..06fdf5133f4 100644
--- a/src/desktop/components/main_layout/templates/minimal_header.jade
+++ b/src/desktop/components/main_layout/templates/minimal_header.jade
@@ -1,7 +1,7 @@
//- Override any locals with `append locals`
block locals
- bodyClass = helpers ? helpers.buildBodyClass(sd, 'body-header-fixed minimal-header') : ''
- - defaultOptions = {modal: true, flash: true, stripe: false, stripev3: false, sailthru: true, marketo: true, quantcast: true}
+ - defaultOptions = {modal: true, flash: true, stripev3: false, sailthru: true, marketo: true, quantcast: false}
- options = options ? Object.assign({}, defaultOptions, options) : defaultOptions
doctype html
@@ -22,8 +22,11 @@ html( data-useragent= userAgent lang="en")
block body
#scripts
- include scripts
- script( src= asset('/assets/main_layout.js') )
- if assetPackage
- script( src=asset('/assets/#{assetPackage}.js') )
+ //- Don't replace this block, rather prepend or append!
block scripts
+ include scripts
+
+ script( src= asset('/assets/main_layout.js') )
+
+ if assetPackage
+ script( src=asset('/assets/#{assetPackage}.js') )
diff --git a/src/desktop/components/main_layout/templates/react_minimal_header.jade b/src/desktop/components/main_layout/templates/react_minimal_header.jade
index 937b5cf0df8..4fbded8e32e 100644
--- a/src/desktop/components/main_layout/templates/react_minimal_header.jade
+++ b/src/desktop/components/main_layout/templates/react_minimal_header.jade
@@ -9,12 +9,15 @@ block head
!= css
block body
- script.
- var __BOOTSTRAP__ = !{JSON.stringify(data)}
-
#react-root
!= body
#react-portal
if jsonLD
include ./json_ld
+
+//- All hydration data should be loaded before React et al
+block prepend scripts
+ script.
+ var __BOOTSTRAP__ = !{JSON.stringify(data)}
+ != scripts
\ No newline at end of file
diff --git a/src/desktop/components/main_layout/templates/react_redesign.jade b/src/desktop/components/main_layout/templates/react_redesign.jade
index fb58fbbe2a7..aaee7f83367 100644
--- a/src/desktop/components/main_layout/templates/react_redesign.jade
+++ b/src/desktop/components/main_layout/templates/react_redesign.jade
@@ -9,12 +9,15 @@ block head
!= css
block body
- script.
- var __BOOTSTRAP__ = !{JSON.stringify(data)}
-
#react-root
!= body
#react-portal
if jsonLD
include ./json_ld
+
+//- All hydration data should be loaded before React et al
+block prepend scripts
+ script.
+ var __BOOTSTRAP__ = !{JSON.stringify(data)}
+ != scripts
\ No newline at end of file
diff --git a/src/desktop/components/main_layout/templates/redesign.jade b/src/desktop/components/main_layout/templates/redesign.jade
index 07568c97a8c..7aa510cf3a9 100644
--- a/src/desktop/components/main_layout/templates/redesign.jade
+++ b/src/desktop/components/main_layout/templates/redesign.jade
@@ -1,7 +1,7 @@
//- Override any locals with `append locals`
block locals
- bodyClass = helpers ? helpers.buildBodyClass(sd, 'body-header-fixed') : '';
- - defaultOptions = {modal: true, flash: true, stripe: false, stripev3: false, sailthru: true, marketo: true, quantcast: true}
+ - defaultOptions = {modal: true, flash: true, stripev3: false, sailthru: true, marketo: true, quantcast: false}
- options = options ? Object.assign({}, defaultOptions, options) : defaultOptions
doctype html
@@ -38,10 +38,12 @@ html(
//- Javascripts
#scripts
- include scripts
- script( src= asset('/assets/main_layout.js') )
+ //- Don't replace this block, rather prepend or append!
+ block scripts
- if assetPackage
- script( src=asset('/assets/#{assetPackage}.js') )
+ include scripts
+ script( src= asset('/assets/main_layout.js') )
+
+ if assetPackage
+ script( src=asset('/assets/#{assetPackage}.js') )
- block scripts
diff --git a/src/desktop/components/main_layout/templates/scripts.jade b/src/desktop/components/main_layout/templates/scripts.jade
index 7ad9256c1be..99af914c072 100644
--- a/src/desktop/components/main_layout/templates/scripts.jade
+++ b/src/desktop/components/main_layout/templates/scripts.jade
@@ -1,4 +1,4 @@
-- defaultOptions = {stripe: false, stripev3: false, sailthru: true, marketo: true, quantcast: true}
+- defaultOptions = {stripev3: false, sailthru: true, marketo: true, quantcast: false}
- options = options ? Object.assign({}, defaultOptions, options) : defaultOptions
//- Common bundle
@@ -118,11 +118,8 @@ if sharify
!= sharify.script()
//- Stripe
-if options.stripe
- script( type="text/javascript", src="https://js.stripe.com/v2/" )
-
if options.stripev3
- script(async, id="stripe-js", src="https://js.stripe.com/v3/")
+ script(id="stripe-js", src="https://js.stripe.com/v3/")
//- Analytics & common asset package
if sd.BROWSER && sd.BROWSER.family != 'Other'
diff --git a/src/desktop/components/react/stitch_components/ReactionArtwork.tsx b/src/desktop/components/react/stitch_components/ReactionArtwork.tsx
deleted file mode 100644
index 1b0f86f6296..00000000000
--- a/src/desktop/components/react/stitch_components/ReactionArtwork.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from "react"
-import { ContextProvider } from "reaction/Artsy"
-import { data as sd } from "sharify"
-import { Artwork } from "reaction/Components/Artwork"
-
-export const ReactionArtwork = props => {
- return (
-
-
-
- )
-}
diff --git a/src/desktop/components/react/stitch_components/ReactionArtworkArtistInfo.tsx b/src/desktop/components/react/stitch_components/ReactionArtworkArtistInfo.tsx
index cb86ab132f5..7a4110fae72 100644
--- a/src/desktop/components/react/stitch_components/ReactionArtworkArtistInfo.tsx
+++ b/src/desktop/components/react/stitch_components/ReactionArtworkArtistInfo.tsx
@@ -1,19 +1,11 @@
import React from "react"
-// @ts-ignore
-import mediator from "desktop/lib/mediator.coffee"
-import { Theme, Box } from "@artsy/palette"
-import { ContextProvider } from "reaction/Artsy"
+import { Box } from "@artsy/palette"
import { ArtistInfoQueryRenderer } from "reaction/Apps/Artwork/Components/ArtistInfo"
-import { data as sd } from "sharify"
export const ReactionArtworkArtistInfo = props => {
return (
-
-
-
-
-
-
-
+
+
+
)
}
diff --git a/src/desktop/components/react/stitch_components/ReactionArtworkDetails.tsx b/src/desktop/components/react/stitch_components/ReactionArtworkDetails.tsx
deleted file mode 100644
index e3679befb13..00000000000
--- a/src/desktop/components/react/stitch_components/ReactionArtworkDetails.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from "react"
-import { Theme } from "@artsy/palette"
-import { ContextProvider } from "reaction/Artsy"
-import { ArtworkDetailsQueryRenderer } from "reaction/Apps/Artwork/Components/ArtworkDetails"
-import { data as sd } from "sharify"
-
-export const ReactionArtworkDetails = props => {
- return (
-
-
-
-
-
- )
-}
diff --git a/src/desktop/components/react/stitch_components/ReactionArtworkGrid.tsx b/src/desktop/components/react/stitch_components/ReactionArtworkGrid.tsx
index 789bca8d573..45354d6b1ce 100644
--- a/src/desktop/components/react/stitch_components/ReactionArtworkGrid.tsx
+++ b/src/desktop/components/react/stitch_components/ReactionArtworkGrid.tsx
@@ -1,7 +1,5 @@
import React, { Component } from "react"
import PropTypes from "prop-types"
-import { ContextProvider } from "reaction/Artsy"
-import { data as sd } from "sharify"
import { mapToRelayConnection } from "./utils/mapToRelayConnection"
import { ArtworkGrid } from "reaction/Components/ArtworkGrid"
@@ -45,10 +43,6 @@ export class ReactionArtworkGrid extends Component {
render() {
const artworks = mapToRelayConnection(this.state.artworks)
- return (
-
-
-
- )
+ return
}
}
diff --git a/src/desktop/components/react/stitch_components/ReactionArtworkSidebarPageviews.tsx b/src/desktop/components/react/stitch_components/ReactionArtworkSidebarPageviews.tsx
index 9445352e6ef..fde12d251f5 100644
--- a/src/desktop/components/react/stitch_components/ReactionArtworkSidebarPageviews.tsx
+++ b/src/desktop/components/react/stitch_components/ReactionArtworkSidebarPageviews.tsx
@@ -1,17 +1,14 @@
import React from "react"
-import { Theme, Box, Separator } from "@artsy/palette"
-import { ContextProvider } from "reaction/Artsy"
+import { Box, Separator } from "@artsy/palette"
import { ArtworkSidebarPageviewsQueryRenderer } from "reaction/Apps/Artwork/Components/ArtworkSidebar/ArtworkSidebarPageviews"
export const ReactionArtworkSidebarPageviews = props => {
return (
-
-
-
-
-
-
-
-
+ <>
+
+
+
+
+ >
)
}
diff --git a/src/desktop/components/react/stitch_components/ReactionFillwidth.tsx b/src/desktop/components/react/stitch_components/ReactionFillwidth.tsx
index 986f343f135..c81dd134b1c 100644
--- a/src/desktop/components/react/stitch_components/ReactionFillwidth.tsx
+++ b/src/desktop/components/react/stitch_components/ReactionFillwidth.tsx
@@ -1,6 +1,4 @@
import React from "react"
-import { ContextProvider } from "reaction/Artsy"
-import { data as sd } from "sharify"
import { mapToRelayConnection } from "./utils/mapToRelayConnection"
export const ReactionFillwidth = props => {
@@ -11,11 +9,7 @@ export const ReactionFillwidth = props => {
const artworks = mapToRelayConnection(props.artworks) // eslint-disable-line
- return (
-
-
-
- )
+ return
} else {
return ""
}
diff --git a/src/desktop/components/react/stitch_components/ReactionUserSettingsPayments.tsx b/src/desktop/components/react/stitch_components/ReactionUserSettingsPayments.tsx
deleted file mode 100644
index 2c148a69ce7..00000000000
--- a/src/desktop/components/react/stitch_components/ReactionUserSettingsPayments.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from "react"
-import { ContextProvider } from "reaction/Artsy"
-import { UserSettingsPaymentsQueryRenderer as UserSettingsPayments } from "reaction/Components/Payment/UserSettingsPayments"
-import { data as sd } from "sharify"
-
-export const ReactionUserSettingsPayments = () => {
- return (
-
-
-
- )
-}
diff --git a/src/desktop/components/react/stitch_components/StitchWrapper.tsx b/src/desktop/components/react/stitch_components/StitchWrapper.tsx
new file mode 100644
index 00000000000..c6bdf451147
--- /dev/null
+++ b/src/desktop/components/react/stitch_components/StitchWrapper.tsx
@@ -0,0 +1,17 @@
+import React from "react"
+import { data as sd } from "sharify"
+import { ContextProvider } from "@artsy/reaction/dist/Artsy"
+import { MediaContextProvider } from "reaction/Utils/Responsive"
+import { Theme } from "@artsy/palette"
+
+const mediator = require("desktop/lib/mediator.coffee")
+
+export const StitchWrapper = props => {
+ return (
+
+
+ {props.children}
+
+
+ )
+}
diff --git a/src/desktop/components/react/stitch_components/index.tsx b/src/desktop/components/react/stitch_components/index.tsx
index 9cdbdc54d7d..bcbba2f22cd 100644
--- a/src/desktop/components/react/stitch_components/index.tsx
+++ b/src/desktop/components/react/stitch_components/index.tsx
@@ -1,18 +1,9 @@
-export { ReactionArtwork as Artwork } from "./ReactionArtwork"
-export {
- ReactionArtworkArtistInfo as ArtworkArtistInfo,
-} from "./ReactionArtworkArtistInfo"
-export {
- ReactionArtworkDetails as ArtworkDetails,
-} from "./ReactionArtworkDetails"
+export { ReactionArtworkArtistInfo as ArtworkArtistInfo } from "./ReactionArtworkArtistInfo"
+export { ArtworkDetailsQueryRenderer as ArtworkDetails } from "reaction/Apps/Artwork/Components/ArtworkDetails"
export { ReactionArtworkGrid as ArtworkGrid } from "./ReactionArtworkGrid"
export { ReactionFillwidth as Fillwidth } from "./ReactionFillwidth"
-export {
- ReactionTooltipQuestion as TooltipQuestion,
-} from "./ReactionTooltipQuestion"
-export {
- ReactionArtworkSidebarPageviews as ArtworkSidebarPageviews,
-} from "./ReactionArtworkSidebarPageviews"
-export {
- ReactionUserSettingsPayments as UserSettingsPayments,
-} from "./ReactionUserSettingsPayments"
+export { ReactionTooltipQuestion as TooltipQuestion } from "./ReactionTooltipQuestion"
+export { ReactionArtworkSidebarPageviews as ArtworkSidebarPageviews } from "./ReactionArtworkSidebarPageviews"
+export { UserSettingsPaymentsQueryRenderer as UserSettingsPayments } from "reaction/Components/Payment/UserSettingsPayments"
+export { StitchWrapper } from './StitchWrapper'
+
diff --git a/src/desktop/components/split_test/running_tests.coffee b/src/desktop/components/split_test/running_tests.coffee
index 0d72add1a6a..979e09c7909 100644
--- a/src/desktop/components/split_test/running_tests.coffee
+++ b/src/desktop/components/split_test/running_tests.coffee
@@ -24,4 +24,14 @@
# this should export empty Object
# module.exports = {}
-module.exports = {}
+module.exports = {
+ artwork_sidebar_pageviews:
+ key: 'artwork_sidebar_pageviews'
+ outcomes: [
+ 'control'
+ 'experiment'
+ ]
+ control_group: 'control'
+ edge: 'experiment'
+ weighting: 'equal'
+}
diff --git a/src/desktop/components/stripe/index.coffee b/src/desktop/components/stripe/index.coffee
deleted file mode 100644
index 8f84134eba9..00000000000
--- a/src/desktop/components/stripe/index.coffee
+++ /dev/null
@@ -1,40 +0,0 @@
-Q = require 'bluebird-q'
-{ reduce, every, identity } = require 'underscore'
-{ STRIPE_PUBLISHABLE_KEY } = require('sharify').data
-
-module.exports =
- initialize: ->
- Stripe.setPublishableKey STRIPE_PUBLISHABLE_KEY
-
- error: (key) -> {
- number: 'Your card number is incorrect.'
- exp: 'Your card’s expiration year is invalid.'
- cvc: 'Your card’s security code is invalid.'
- }[key]
-
- validate: validate = ({ number, exp, cvc }) -> [
- { name: 'number', value: Stripe.card.validateCardNumber number }
- { name: 'exp', value: Stripe.card.validateExpiry exp }
- { name: 'cvc', value: Stripe.card.validateCVC cvc }
- ]
-
- isValid: ->
- every (validate arguments...), ({ value }) -> value
-
- serialize: ($form) ->
- reduce $form.find('[data-stripe]'), (memo, el) ->
- $el = $(el)
- memo[$el.data 'stripe'] = $el.val()
- memo
- , {}
-
- tokenize: (obj) ->
- Q.promise (resolve, reject) ->
- Stripe.card.createToken obj, (status, data) ->
- if status is 200
- resolve data
- else
- reject data.error.message
-
- cardType: (number) ->
- Stripe.card.cardType number
diff --git a/src/desktop/components/stripe/test/index.coffee b/src/desktop/components/stripe/test/index.coffee
deleted file mode 100644
index a221e3687ca..00000000000
--- a/src/desktop/components/stripe/test/index.coffee
+++ /dev/null
@@ -1,73 +0,0 @@
-benv = require 'benv'
-sinon = require 'sinon'
-stripe = require '../index'
-Stripe = {}
-
-describe 'stripe', ->
- before (done) ->
- benv.setup ->
- benv.expose
- $: benv.require 'jquery'
- Stripe: Stripe
- done()
-
- after ->
- benv.teardown()
-
- beforeEach ->
- Stripe.card =
- validateCardNumber: sinon.stub()
- validateExpiry: sinon.stub()
- validateCVC: sinon.stub()
- createToken: sinon.stub()
- cardType: sinon.stub()
-
- describe '#isValid', ->
- beforeEach ->
- @card =
- number: '6666666666666666'
- exp: '10/2020'
- cvc: '666'
-
- it 'returns true if all the validators are also true', ->
- Stripe.card.validateCardNumber.returns true
- Stripe.card.validateExpiry.returns true
- Stripe.card.validateCVC.returns true
-
- stripe.isValid @card
- .should.be.true()
-
- it 'returns false if any one of the validators is false', ->
- Stripe.card.validateCardNumber.returns true
- Stripe.card.validateExpiry.returns false
- Stripe.card.validateCVC.returns true
-
- stripe.isValid @card
- .should.be.false()
-
- describe '#serialize', ->
- it 'pulls out data from sensitive fields marked with the `data-stripe` attribute', ->
- $el = $ """
-
- """
-
- $el.find('[name="foo"]').val 'Bar'
- $el.find('[data-stripe="cc_number"]').val '6666666666666666'
- $el.find('[data-stripe="cvc"]').val '666'
-
- stripe.serialize $el
- .should.eql
- cc_number: '6666666666666666'
- cvc: '666'
-
- describe '#tokenize', ->
- it 'wraps Stripe’s `createToken` with a Promise', ->
- Stripe.card.createToken.yields 200, id: 'existy'
-
- stripe.tokenize {}
- .then ({ id }) ->
- id.should.equal 'existy'
diff --git a/src/desktop/config.coffee b/src/desktop/config.coffee
index f6dadb27368..784df679b20 100755
--- a/src/desktop/config.coffee
+++ b/src/desktop/config.coffee
@@ -17,7 +17,7 @@ module.exports =
ARTSY_ID: null
ARTSY_SECRET: null
BIDDER_H1_COPY: 'Please enter your credit card details'
- BIDDER_H2_COPY: 'NOTE: All bidders need to have a valid payment method on file. Winning bidders will have the opportunity to pay by credit card, check or wire transfer.'
+ BIDDER_H2_COPY: 'A valid credit card is required to bid. If you win, you’ll have the opportunity to pay by credit card, check or wire transfer after the sale closes.'
CDN_URL: 'https://d1s2w0upia4e9w.cloudfront.net'
CMS_URL: 'https://cms.artsy.net'
COLLECT_PAGE_TITLES_URL: 'https://s3.amazonaws.com/artsy-data/collect/collect.json'
@@ -26,7 +26,6 @@ module.exports =
CONVECTION_APP_ID: null
CONVECTION_GEMINI_APP: 'convection-staging'
COOKIE_DOMAIN: null
- CRITEO_ARTWORKS_ACCOUNT_NUMBER: '35250'
CRITEO_AUCTIONS_ACCOUNT_NUMBER: '28539'
DD_APM_ENABLED: null
DD_TRACE_AGENT_HOSTNAME: 'localhost'
@@ -42,6 +41,8 @@ module.exports =
EMBEDLY_KEY: 'a1f82558d8134f6cbebceb9e67d04980'
EOY_2016_ARTICLE: null
EOY_2016: '5829db77b5989e6f98f779a5'
+ EOY_2018_ARTISTS: '5bf30690d8b9430baaf6c6de'
+ EOY_2018_CULTURE: '5bf306aad8b9430baaf6c6df'
EF_VENICE: '58f5eb75faef6a3a8e7fe1ad'
EF_GUCCI: '5a009372c88a280f5e9efa7e'
EF_VIDEO_GUIDE: '5901d64b4682400017f0e3cb'
@@ -67,8 +68,11 @@ module.exports =
GEOIP_ENDPOINT: 'https://artsy-geoip.herokuapp.com/'
GOOGLE_ADWORDS_ID: null
GOOGLE_MAPS_API_KEY: null
- INTERCOM_APP_ID: null
- INTERCOM_ENABLED: false
+ INTERCOM_SELLER_APP_ID: null
+ INTERCOM_SELLER_ENABLED: false
+ INTERCOM_BUYER_APP_ID: null
+ INTERCOM_BUYER_APP_SECRET: null
+ INTERCOM_BUYER_ENABLED: false
IMAGE_PROXY: 'GEMINI'
IPHONE_APP_COPY: 'Download the iPhone app: https://itunes.apple.com/us/app/artsy-art-world-in-your-pocket/id703796080?ls=1&mt=8'
IP_BLACKLIST: ''
diff --git a/src/desktop/index.js b/src/desktop/index.js
index 97dc3443e3a..e6749f911e1 100644
--- a/src/desktop/index.js
+++ b/src/desktop/index.js
@@ -1,5 +1,6 @@
import * as modules from "./lib/global_react_modules"
import { data as sd } from "sharify"
+
const app = (module.exports = require("express")())
// NOTE:
@@ -7,7 +8,12 @@ const app = (module.exports = require("express")())
// TODO: Move to src/lib/middleware/locals once done developing; this is just so
// we can get hot module reloading which only works in /desktop and /mobile
-app.use(require("@artsy/stitch/dist/server").middleware(modules))
+app.use(
+ require("@artsy/stitch/dist/server").middleware({
+ modules,
+ Wrapper: modules.StitchWrapper,
+ })
+)
// Apps with hardcoded routes or "RESTful" routes
app.use(require("./apps/home"))
@@ -16,16 +22,16 @@ app.use(require("./apps/apply"))
app.use(require("./apps/auctions"))
app.use(require("./apps/auctions2"))
app.use(require("./apps/auction_lots"))
-app.use(require("./apps/artist/server"))
+app.use(require("./apps/artist/server").app)
app.use(require("./apps/artists"))
app.use(require("./apps/auction"))
app.use(require("./apps/auction_support"))
app.use(require("./apps/artwork"))
-app.use(require("./apps/artwork2/server"))
+app.use(require("./apps/artwork2/server").app)
app.use(require("./apps/about"))
app.use(require("./apps/collect_art"))
-app.use(require("./apps/collect2/server"))
-app.use(require("./apps/collections/server"))
+app.use(require("./apps/collect2/server").app)
+app.use(require("./apps/collections/server").app)
app.use(require("./apps/categories"))
app.use(require("./apps/consign"))
app.use(require("./apps/contact"))
@@ -88,4 +94,4 @@ app.use(require("./apps/user"))
// Examples
app.use(require("./apps/react_example"))
-app.use(require("./apps/isomorphic-relay-example/server"))
+app.use(require("./apps/isomorphic-relay-example/server").app)
diff --git a/src/desktop/lib/buildServerAppContext.ts b/src/desktop/lib/buildServerAppContext.ts
index 45e810322d2..57a696c6f13 100644
--- a/src/desktop/lib/buildServerAppContext.ts
+++ b/src/desktop/lib/buildServerAppContext.ts
@@ -1,11 +1,6 @@
// @ts-ignore
import mediator from "desktop/lib/mediator.coffee"
-import { Request as ExpressRequest, Response as ExpressResponse } from "express"
-
-interface Request extends ExpressRequest {
- user: any
-}
-type Response = ExpressResponse
+import { Request, Response } from "express"
/**
* Builds initial context for Reaction components from server load. Put commonly
diff --git a/src/desktop/lib/global_client_setup.coffee b/src/desktop/lib/global_client_setup.coffee
index 8b6174a5cb8..73c56fb6b8c 100644
--- a/src/desktop/lib/global_client_setup.coffee
+++ b/src/desktop/lib/global_client_setup.coffee
@@ -102,12 +102,13 @@ mountStitchBlocks = ->
{components, mountOnClient} = componentRenderer({
mode: 'client',
modules: globalReactModules
+ Wrapper: globalReactModules.StitchWrapper
})
sd.stitch.renderQueue.forEach (block) ->
mountOnClient(block)
# Mount renderer for runtime client-side templates. NOTE: must be included
- # in template when rendering data; e.g., html = myTemplate({ data, reaction })
+ # in template when rendering data; e.g., html = myTemplate({ data, stitch })
sd.stitch.components = components
diff --git a/src/desktop/models/fair.coffee b/src/desktop/models/fair.coffee
index c02808d936b..742c79432fe 100644
--- a/src/desktop/models/fair.coffee
+++ b/src/desktop/models/fair.coffee
@@ -216,17 +216,13 @@ module.exports = class Fair extends Backbone.Model
@get('published') and
not @related().profile.get('published')
- hasStarted: ->
- Date.parse(@get('start_at')) < new Date
-
- hasNotStarted: ->
- Date.parse(@get('start_at')) > new Date
-
isNotOver: ->
- Date.parse(@get('end_at')) > new Date
+ not @isOver()
isOver: ->
- Date.parse(@get('end_at')) < new Date
+ endOfFair = moment.utc(@get('end_at')).endOf("day")
+ now = moment()
+ now.isAfter(endOfFair)
isCurrent: ->
@isEligible() and @isNotOver()
diff --git a/src/desktop/test/models/fair.coffee b/src/desktop/test/models/fair.coffee
index 711c8329ef1..8d86da00f5a 100644
--- a/src/desktop/test/models/fair.coffee
+++ b/src/desktop/test/models/fair.coffee
@@ -15,6 +15,15 @@ describe 'Fair', ->
afterEach ->
Backbone.sync.restore()
+ describe '#isNotOver', ->
+ it 'checks the UTC timezone of a fair\'s end_at field compared to now', ->
+ fair = new Fair fabricate('fair', end_at: '2018-12-13T22:00:00-05:00')
+ utcMoment = moment.utc('2018-12-14T07:00:00-00:00')
+ realNow = Date.now
+ Date.now = () -> utcMoment
+ fair.isNotOver().should.equal true
+ Date.now = realNow
+
describe '#nameSansYear', ->
it 'returns the name without the year', ->
new Fair name: 'Foo Fair 2015'
diff --git a/src/desktop/apps/gallery_partnerships/client/intercom.js b/src/lib/components/intercom/index.js
similarity index 63%
rename from src/desktop/apps/gallery_partnerships/client/intercom.js
rename to src/lib/components/intercom/index.js
index 725e731e579..b88ca180cf2 100644
--- a/src/desktop/apps/gallery_partnerships/client/intercom.js
+++ b/src/lib/components/intercom/index.js
@@ -1,9 +1,16 @@
import { data as sd } from "sharify"
-window.intercomSettings = {
- app_id: sd.INTERCOM_APP_ID,
-}
-;(function() {
+export const intercom = function(appID, userData = null) {
+ window.intercomSettings = {
+ app_id: appID,
+ }
+
+ // Logged-in user w/ identity verification
+ if (userData) {
+ window.intercomSettings.name = userData.name
+ window.intercomSettings.email = userData.email
+ window.intercomSettings.user_hash = userData.userHash
+ }
var w = window
var ic = w.Intercom
if (typeof ic === "function") {
@@ -23,7 +30,7 @@ window.intercomSettings = {
var s = d.createElement("script")
s.type = "text/javascript"
s.async = true
- s.src = `https://widget.intercom.io/widget/${sd.INTERCOM_APP_ID}`
+ s.src = `https://widget.intercom.io/widget/${appID}`
var x = d.getElementsByTagName("script")[0]
x.parentNode.insertBefore(s, x)
}
@@ -33,4 +40,4 @@ window.intercomSettings = {
w.addEventListener("load", l, false)
}
}
-})()
+}
diff --git a/src/lib/intercom.ts b/src/lib/intercom.ts
new file mode 100644
index 00000000000..ce2e86918dc
--- /dev/null
+++ b/src/lib/intercom.ts
@@ -0,0 +1,29 @@
+const { intercom } = require("./components/intercom/index")
+import { data as sd } from "sharify"
+
+// We show an Intercom chat widget on artwork pages where the
+// artwork is commercial (offerable or acquireable).
+export function enableIntercom({ is_offerable, is_acquireable }) {
+ const {
+ INTERCOM_BUYER_ENABLED,
+ INTERCOM_BUYER_APP_ID,
+ INTERCOM_BUYER_HASH,
+ CURRENT_USER,
+ } = sd
+
+ const intercomEnabled = INTERCOM_BUYER_ENABLED && INTERCOM_BUYER_APP_ID
+ const isCommercialWork = is_acquireable || is_offerable
+
+ if (isCommercialWork && intercomEnabled) {
+ if (CURRENT_USER) {
+ const userData = {
+ name: CURRENT_USER.name,
+ email: CURRENT_USER.email,
+ userHash: INTERCOM_BUYER_HASH,
+ }
+ intercom(INTERCOM_BUYER_APP_ID, userData)
+ } else {
+ intercom(INTERCOM_BUYER_APP_ID)
+ }
+ }
+}
diff --git a/src/lib/memory_profiler.js b/src/lib/memory_profiler.js
index 60658b97aca..8085f315310 100644
--- a/src/lib/memory_profiler.js
+++ b/src/lib/memory_profiler.js
@@ -1,7 +1,7 @@
const chalk = require("chalk")
const heapdump = require("heapdump")
const knox = require("knox")
-const memwatch = require("memwatch-ng")
+const memwatch = require("@airbnb/node-memwatch")
const moment = require("moment")
const os = require("os")
const path = require("path")
diff --git a/src/lib/middleware/intercom.ts b/src/lib/middleware/intercom.ts
new file mode 100644
index 00000000000..ce656a9a098
--- /dev/null
+++ b/src/lib/middleware/intercom.ts
@@ -0,0 +1,14 @@
+import * as crypto from "crypto"
+// @ts-ignore
+import { INTERCOM_BUYER_APP_SECRET } from "../../config"
+
+export function addIntercomUserHash(req, res, next) {
+ console.log(INTERCOM_BUYER_APP_SECRET)
+ if (req.user && INTERCOM_BUYER_APP_SECRET) {
+ res.locals.sd.INTERCOM_BUYER_HASH = crypto
+ .createHmac("sha256", INTERCOM_BUYER_APP_SECRET)
+ .update(req.user.get("email"))
+ .digest("hex")
+ }
+ return next()
+}
diff --git a/src/lib/setup.js b/src/lib/setup.js
index defe8f93308..eb1a14c2473 100644
--- a/src/lib/setup.js
+++ b/src/lib/setup.js
@@ -44,6 +44,7 @@ import backboneErrorHelper from "./middleware/backbone_error_helper"
import CurrentUser from "./current_user"
import splitTestMiddleware from "../desktop/components/split_test/middleware"
import marketingModals from "./middleware/marketing_modals"
+import { addIntercomUserHash } from "./middleware/intercom"
import config from "../config"
import compression from "compression"
@@ -221,6 +222,7 @@ export default function(app) {
app.use(logger)
app.use(unsupportedBrowserCheck)
app.use(splitTestMiddleware)
+ app.use(addIntercomUserHash)
if (DD_APM_ENABLED) {
ddTracer.init({
diff --git a/src/lib/setup_sharify.js b/src/lib/setup_sharify.js
index 8c78af1d3bd..2efef1ea650 100644
--- a/src/lib/setup_sharify.js
+++ b/src/lib/setup_sharify.js
@@ -34,7 +34,6 @@ sharify.data = _.extend(
"CONVECTION_APP_URL",
"CONVECTION_APP_ID",
"CONVECTION_GEMINI_APP",
- "CRITEO_ARTWORKS_ACCOUNT_NUMBER",
"CRITEO_AUCTIONS_ACCOUNT_NUMBER",
"DISABLE_IMAGE_PROXY",
"EDITORIAL_ADMINS",
@@ -46,6 +45,8 @@ sharify.data = _.extend(
"ENABLE_EXPERIMENTAL_STITCH_INJECTION",
"EOY_2016_ARTICLE",
"EOY_2016",
+ "EOY_2018_ARTISTS",
+ "EOY_2018_CULTURE",
"EF_GUCCI",
"EF_VENICE",
"EF_VIDEO_GUIDE",
@@ -69,8 +70,10 @@ sharify.data = _.extend(
"GOOGLE_MAPS_API_KEY",
"GOOGLE_ADWORDS_ID",
"IMAGE_PROXY",
- "INTERCOM_APP_ID",
- "INTERCOM_ENABLED",
+ "INTERCOM_SELLER_APP_ID",
+ "INTERCOM_SELLER_ENABLED",
+ "INTERCOM_BUYER_APP_ID",
+ "INTERCOM_BUYER_ENABLED",
"MARKETING_SIGNUP_MODALS",
"MAX_POLLS_FOR_MAX_BIDS",
"METAPHYSICS_ENDPOINT",
diff --git a/src/mobile/analytics/criteo.js b/src/mobile/analytics/criteo.js
index 674f09e2a11..a8fd35865e3 100644
--- a/src/mobile/analytics/criteo.js
+++ b/src/mobile/analytics/criteo.js
@@ -64,7 +64,7 @@ if (pathSplit[1] === "auctions") {
)
} else {
window.criteo_q.push(
- { event: "setAccount", account: sd.CRITEO_ARTWORKS_ACCOUNT_NUMBER },
+ { event: "setAccount", account: sd.CRITEO_AUCTIONS_ACCOUNT_NUMBER },
{ event: "setSiteType", type: "m" },
{ event: "setEmail", email: userEmail },
{ event: "viewItem", item: sd.ARTWORK._id }
@@ -75,7 +75,7 @@ if (pathSplit[1] === "auctions") {
// https://www.artsy.net/collect - (ARTWORKS viewHome)
// 0 1
window.criteo_q.push(
- { event: "setAccount", account: sd.CRITEO_ARTWORKS_ACCOUNT_NUMBER },
+ { event: "setAccount", account: sd.CRITEO_AUCTIONS_ACCOUNT_NUMBER },
{ event: "setSiteType", type: "m" },
{ event: "setEmail", email: userEmail },
{ event: "viewHome" }
@@ -84,7 +84,7 @@ if (pathSplit[1] === "auctions") {
// https://www.artsy.net/artist/:artist_id - (ARTWORKS viewList)
// 0 1 2
window.criteo_q.push(
- { event: "setAccount", account: sd.CRITEO_ARTWORKS_ACCOUNT_NUMBER },
+ { event: "setAccount", account: sd.CRITEO_AUCTIONS_ACCOUNT_NUMBER },
{ event: "setSiteType", type: "m" },
{ event: "setEmail", email: userEmail },
{
diff --git a/src/mobile/apps/art_fairs/helpers.coffee b/src/mobile/apps/art_fairs/helpers.coffee
index 7e95a0391be..5aef3397fbd 100644
--- a/src/mobile/apps/art_fairs/helpers.coffee
+++ b/src/mobile/apps/art_fairs/helpers.coffee
@@ -1,5 +1,6 @@
_ = require 'underscore'
DateHelpers = require '../../components/util/date_helpers.coffee'
+moment = require 'moment'
module.exports =
@@ -10,13 +11,15 @@ module.exports =
fair.is_published and fair.profile?.is_published
isNotOver: (fair) ->
- Date.parse(fair.end_at) > new Date
+ not @isOver(fair)
isPast: (fair) ->
@isEligible(fair) and @isOver(fair)
isOver: (fair) ->
- Date.parse(fair.end_at) < new Date
+ endOfFair = moment.utc(fair.end_at).endOf("day")
+ now = moment()
+ now.isAfter(endOfFair)
isUpcoming: (fair) ->
@isEventuallyEligible(fair) and @isNotOver(fair)
diff --git a/src/mobile/apps/art_fairs/test/routes.coffee b/src/mobile/apps/art_fairs/test/routes.coffee
index 933018bc3cf..bc634a72d4f 100644
--- a/src/mobile/apps/art_fairs/test/routes.coffee
+++ b/src/mobile/apps/art_fairs/test/routes.coffee
@@ -22,10 +22,6 @@ describe '#index', ->
fabricate('fair', profile: profile, id: _.uniqueId('past'), is_published: true, has_full_feature: true, has_listing: true, organizer: fabricate('fair_organizer'), end_at: moment().subtract(10, 'days'))
@upcomingFairs = _.times 3, ->
fabricate('fair', profile: unpublished_profile, id: _.uniqueId('upcoming'), is_published: true, has_full_feature: true, has_listing: true, organizer: null, end_at: moment().add(10, 'days'))
- @invalidFairs = [
- fabricate 'fair', id: _.uniqueId('invalid'), is_published: false
- fabricate 'fair', id: _.uniqueId('invalid'), is_published: true, has_full_feature: false, has_listing: false
- ]
describe 'with fairs', ->
@@ -35,7 +31,6 @@ describe '#index', ->
@currentFairs
@pastFairs
@upcomingFairs
- @invalidFairs
]
routes.__set__ 'metaphysics', => Q.resolve { fairs: @fairs }
diff --git a/src/mobile/apps/artwork/client/index.coffee b/src/mobile/apps/artwork/client/index.coffee
index 567d334ecf9..e08a19fca3f 100644
--- a/src/mobile/apps/artwork/client/index.coffee
+++ b/src/mobile/apps/artwork/client/index.coffee
@@ -9,7 +9,7 @@ Artwork = require '../../../models/artwork.coffee'
Artworks = require '../../../collections/artworks.coffee'
fetchArtworkBuckets = require '../components/related_artworks/index.coffee'
{ recordArtworkView } = require 'lib/components/record_artwork_view'
-
+{ enableIntercom } = require 'lib/intercom'
module.exports.init = ->
bootstrap()
artworkTabsView()
@@ -17,6 +17,7 @@ module.exports.init = ->
user = CurrentUser.orNull()
user.initializeDefaultArtworkCollection() if user
recordArtworkView(sd.ARTWORK._id, user)
+ enableIntercom(sd.ARTWORK)
new ArtworkImageView
artwork: sd.ARTWORK
diff --git a/src/mobile/apps/artwork/components/bid/index.jade b/src/mobile/apps/artwork/components/bid/index.jade
index 08569cbc8f6..a90a266bda5 100644
--- a/src/mobile/apps/artwork/components/bid/index.jade
+++ b/src/mobile/apps/artwork/components/bid/index.jade
@@ -2,12 +2,13 @@
if artwork.auction
.js-artwork-auction-container
.artwork-auction-bid-module
- if artwork.auction.is_open && !artwork.auction.is_live_open && !artwork.is_sold && !helpers.moment().isAfter(artwork.auction.end_at)
+ if artwork.auction.is_preview || artwork.auction.is_open && !artwork.auction.is_live_open && !artwork.is_sold && !helpers.moment().isAfter(artwork.auction.end_at)
.artwork-auction-bid-module__current-bid
include ./templates/bid.jade
- .artwork-auction-bid-module__bid-form
- include ./templates/bid_button.jade
+ if !artwork.auction.is_preview
+ .artwork-auction-bid-module__bid-form
+ include ./templates/bid_button.jade
if artwork.auction.is_with_buyers_premium
.artwork-auction-buyers-premium This work has a
diff --git a/src/mobile/apps/artwork/components/meta_data/templates/price.jade b/src/mobile/apps/artwork/components/meta_data/templates/price.jade
index 0e020ee39ea..193d5dffd3e 100644
--- a/src/mobile/apps/artwork/components/meta_data/templates/price.jade
+++ b/src/mobile/apps/artwork/components/meta_data/templates/price.jade
@@ -2,7 +2,7 @@ if artwork.sale_message
.artwork-meta-data-price
if artwork.sale_message
.sale_message= artwork.sale_message
- if artwork.price && artwork.availability !== 'sold'
+ if artwork.is_acquireable || artwork.is_offerable
.shipping-info
| #{artwork.shippingInfo}
if artwork.shippingOrigin
diff --git a/src/mobile/apps/artwork/components/meta_data/test/template.coffee b/src/mobile/apps/artwork/components/meta_data/test/template.coffee
index 52e354b43d0..bf84f2f5583 100644
--- a/src/mobile/apps/artwork/components/meta_data/test/template.coffee
+++ b/src/mobile/apps/artwork/components/meta_data/test/template.coffee
@@ -33,6 +33,37 @@ describe 'Artwork metadata templates', ->
$ = cheerio.load(@html)
$('.sale_message').text().should.equal '$4,000'
+ describe 'artwork with shipping information', ->
+ it 'shows shipping information for ecommerce artworks', ->
+ @artwork.is_acquireable = true
+ @artwork.sale_message = '$5,000'
+ @artwork.shippingInfo = "Shipping: $50 continental US, $100 rest of world"
+ @artwork.shippingOrigin = "New York, New York, US"
+
+ html = render('price')(
+ artwork: @artwork
+ sd: {}
+ asset: (->)
+ )
+
+ $ = cheerio.load html
+ $('.shipping-info').length.should.eql 1
+
+ it 'does not show shipping information when unenrolled from ecommerce programs', ->
+ @artwork.is_acquireable = false
+ @artwork.sale_message = '$5,000'
+ @artwork.shippingInfo = "Shipping: $50 continental US, $100 rest of world"
+ @artwork.shippingOrigin = "New York, New York, US"
+
+ html = render('price')(
+ artwork: @artwork
+ sd: {}
+ asset: (->)
+ )
+
+ $ = cheerio.load html
+ $('.shipping-info').length.should.eql 0
+
describe 'artwork without sale message', ->
beforeEach ->
@html = render('price')(
diff --git a/src/mobile/apps/auction_support/client/registration_form.coffee b/src/mobile/apps/auction_support/client/registration_form.coffee
index 9a9acb607a8..92c53a1dfc4 100644
--- a/src/mobile/apps/auction_support/client/registration_form.coffee
+++ b/src/mobile/apps/auction_support/client/registration_form.coffee
@@ -25,28 +25,37 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
@$conditionsCheckbox = @$('.artsy-checkbox')
@$submit = @$('.registration-form-content .avant-garde-box-button')
@setUpFields()
+ @setUpStripe()
setUpFields: ->
@fields =
'name on card': { el: @$('input[name=card_name]'), validator: @isPresent }
- 'card number': { el: @$('input[name=card_number]'), validator: @isCardNumber }
- 'security code': { el: @$('input[name=card_security_code]'), validator: @isPresent }
telephone: { el: @$('input.telephone'), validator: @isPresent }
- month: { el: @$('.card-expiration .month select'), validator: @isPresent }
- year: { el: @$('.card-expiration .year select'), validator: @isPresent }
street: { el: @$('input.street'), validator: @isPresent, label: 'address' }
city: { el: @$('input.city'), validator: @isPresent, label: 'city' }
state: { el: @$('input.region'), validator: @isState, label: 'state' }
zip: { el: @$('input.postal-code'), validator: @isZip }
@internationalizeFields()
+ setUpStripe: ->
+ @stripe = Stripe(STRIPE_PUBLISHABLE_KEY)
+ elements = @stripe.elements()
+ @card = elements.create('card', {
+ style: {
+ base: {
+ fontFamily: '"Adobe Garamond W08", Georgia, Serif',
+ fontSize: '16px',
+ '::placeholder': {
+ color: '#cccccc',
+ },
+ }
+ }
+ })
+ @card.update({ hidePostalCode: true })
+ @card.mount('#card-element')
cardData: ->
name: @fields['name on card'].el.val()
- number: @fields['card number'].el.val()
- exp_month: @fields.month.el.first().val()
- exp_year: @fields.year.el.last().val()
- cvc: @fields['security code'].el.val()
address_line1: @fields.street.el.val()
address_city: @fields.city.el.val()
address_state: @fields.state.el.val()
@@ -56,12 +65,12 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
tokenizeCard: ->
Q.Promise (resolve, reject) =>
# Attempt to tokenize the credit card through Stripe
- Stripe.setPublishableKey STRIPE_PUBLISHABLE_KEY
- Stripe.card.createToken @cardData(), (status, data) =>
- if status is 200
- resolve data
+ @stripe.createToken(@card, @cardData()).then (result) ->
+ if result.token
+ resolve result
else
- reject data.error.message
+ reject result.error.message
+
.then (data) =>
analyticsHooks.trigger 'registration:validated'
@@ -69,7 +78,7 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
Q.Promise (resolve, reject) =>
card = new Backbone.Model
card.url = "#{sd.API_URL}/api/v1/me/credit_cards"
- card.save { token: data.id, provider: 'stripe' },
+ card.save { token: data.token.id, provider: 'stripe' },
success: (creditCard) =>
if creditCard.get("address_zip_check") == "fail"
reject @errors.badZip
@@ -77,7 +86,8 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
reject @errors.badSecurityCode
else
resolve(creditCard)
- error: (m, xhr) => reject(xhr.responseJSON?.message)
+ error: (m, xhr) =>
+ reject(xhr.responseJSON?.message)
.then =>
analyticsHooks.trigger 'registration:submitted'
@@ -113,7 +123,6 @@ module.exports = class RegistrationForm extends ErrorHandlingForm
onSubmit: (event) ->
event.preventDefault()
return unless @validateAcceptConditions()
-
analyticsHooks.trigger 'registration:submitted-address'
@loadingLock @$submit, =>
diff --git a/src/mobile/apps/auction_support/stylesheets/index.styl b/src/mobile/apps/auction_support/stylesheets/index.styl
index dd31c9b26e0..1ce9d834ddd 100644
--- a/src/mobile/apps/auction_support/stylesheets/index.styl
+++ b/src/mobile/apps/auction_support/stylesheets/index.styl
@@ -90,25 +90,18 @@ checkbox-size = 20px
.credit-card-input-section
margin-top 10px
- .card-expiration
- .month, .year
- width 49%
- display inline-block
- vertical-align top
- .month
- margin-right 2%
.registration-form-section
margin-top 20px
- .card-expiration.credit-card-input-section, .card-security-code.credit-card-input-section, .postal-code.credit-card-input-section, .region.credit-card-input-section
+ .postal-code.credit-card-input-section, .region.credit-card-input-section
display inline-block
vertical-align top
.postal-code.credit-card-input-section, .region.credit-card-input-section
width 49%
- .card-expiration.credit-card-input-section, .region.credit-card-input-section
+ .region.credit-card-input-section
margin-right 2%
.avant-garde-box-button
@@ -128,11 +121,15 @@ checkbox-size = 20px
.error
color red-color
- .card-security-code.credit-card-input-section
- width 36%
- display block
- input
- padding 10px 0 11px 0
- .card-expiration
- width 62%
+#card-element
+ border 2px solid light-gray-border-color
+ box-sizing border-box
+ width 100%
+ padding 10px
+ height 44px
+
+#card-element.StripeElement--focus
+ border-color highlight-color
+ outline none
+
diff --git a/src/mobile/apps/auction_support/test/client/registration_form.coffee b/src/mobile/apps/auction_support/test/client/registration_form.coffee
index d0593189c55..f7fa43640fe 100644
--- a/src/mobile/apps/auction_support/test/client/registration_form.coffee
+++ b/src/mobile/apps/auction_support/test/client/registration_form.coffee
@@ -16,9 +16,15 @@ describe 'RegistrationForm', ->
benv.expose
$: benv.require('jquery'),
Stripe: @Stripe =
- setPublishableKey: sinon.stub()
- card:
- createToken: sinon.stub()
+ sinon.stub().returns({
+ createToken: sinon.stub().returns(Promise.resolve({ token: { id: '123' } }))
+ elements: sinon.stub().returns({
+ create: sinon.stub().returns({
+ update: sinon.stub()
+ mount: sinon.stub()
+ })
+ })
+ })
Backbone.$ = $
done()
@@ -26,7 +32,7 @@ describe 'RegistrationForm', ->
benv.teardown()
beforeEach (done) ->
- @submitStub = sinon.stub(Backbone, 'sync')#.yieldsTo('success')
+ @submitStub = sinon.stub(Backbone, 'sync')
@sale = new Sale fabricate 'sale'
@@ -53,10 +59,6 @@ describe 'RegistrationForm', ->
@acceptTerms = => @view.$acceptConditions.prop('checked', true)
@submitValidForm = =>
@view.$('input[name="card_name"]').val 'Foo Bar'
- @view.$('select[name="card_expiration_month"]').val '1'
- @view.$('select[name="card_expiration_year"]').val '2024'
- @view.$('input[name="card_number"]').val '4111111111111111'
- @view.$('input[name="card_security_code"]').val '123'
@view.$('input[name="address[street]"]').val '456 Foo Bar Ln.'
@view.$('input[name="address[city]"]').val 'Foobarrington'
@view.$('input[name="address[region]"]').val 'FB'
@@ -65,8 +67,6 @@ describe 'RegistrationForm', ->
@view.$submit.click()
it 'still succeeds if the API throws an error for having already created a bidder', (done) ->
- # Successfully create a stripe token
- @Stripe.card.createToken.callsArgWith(1, 200, {})
# Successfully save phone number
Backbone.sync.onFirstCall().yieldsTo('success')
# Successfully save credit card
@@ -88,8 +88,6 @@ describe 'RegistrationForm', ->
@view.on "submitted", =>
html = @view.$el.html()
html.should.containEql 'Invalid name on card'
- html.should.containEql 'Invalid card number'
- html.should.containEql 'Invalid security code'
html.should.containEql 'Invalid city'
html.should.containEql 'Invalid state'
html.should.containEql 'Invalid zip'
@@ -98,32 +96,29 @@ describe 'RegistrationForm', ->
done()
it 'lets the user resubmit a corrected form', ->
- # Submit a bad form
+ @acceptTerms()
+ # Submit a bad form
@view.$submit.length.should.be.ok()
@view.$submit.click()
- @view.on "submitted", =>
+ @view.once "submitted", =>
html = @view.$el.html()
html.should.containEql 'Please review the error(s) above and try again.'
# Now submit a good one
-
- # Successfully create a stripe token
- @Stripe.card.createToken.callsArgWith(1, 200, {})
- # Successfully save phone number
- Backbone.sync.onFirstCall().yieldsTo('success')
- # Successfully save credit card
- Backbone.sync.onSecondCall().yieldsTo('success')
- # Successfully create the bidder
- Backbone.sync.onThirdCall().yieldsTo('success')
-
- @acceptTerms()
+ Backbone.sync
+ .yieldsTo 'success', {} # savePhoneNumber success
+ .onCall 1
+ .yieldsTo 'success', { get: () -> 'pass' } # credit card save passes
+ .onCall 2
+ .yieldsTo 'success', {}
+
+ @view.$submit.removeClass('is-loading')
@submitValidForm()
- @view.on "submitted", =>
- @Stripe.card.createToken.args[0][1](200, {})
+ @view.once "submitted", =>
# Saves the phone number
- Backbone.sync.args[0][1].changed.phone.should.equal '555-555-5555'
+ Backbone.sync.args[0][2].attrs.phone.should.equal '555-555-5555'
# Saves the credit card
Backbone.sync.args[1][1].url.should.containEql '/api/v1/me/credit_cards'
@@ -134,8 +129,6 @@ describe 'RegistrationForm', ->
Backbone.sync.args[2][2].url.should.containEql '/api/v1/bidder'
it 'submits the form correctly', ->
- # Successfully create a stripe token
- @Stripe.card.createToken.callsArgWith(1, 200, {})
# Successfully save phone number
Backbone.sync.onFirstCall().yieldsTo('success')
# Successfully save credit card
diff --git a/src/mobile/components/credit_card/templates/credit_card.jade b/src/mobile/components/credit_card/templates/credit_card.jade
index 8a18925db50..6eba40b0714 100644
--- a/src/mobile/components/credit_card/templates/credit_card.jade
+++ b/src/mobile/components/credit_card/templates/credit_card.jade
@@ -2,21 +2,6 @@
label( for='card_name' ) Name on Card
input.bordered-input( type='text', name='card_name', value=name, autocomplete='cc-name' )
-.card-number.credit-card-input-section
- label( for='card_number' ) Credit Card Number
- input.bordered-input( type='tel', name='card_number', value=number, autocomplte="cc-number", novalidate=true, pattern="\d*" )
-
-.card-expiration.credit-card-input-section
- label( for='card_expiration' ) Expiration
- .month
- select.bordered-select( name='card_expiration_month', autocomplete="cc-exp-month" )
- each month in monthRange
- option( value=month )!= month
- .year
- select.bordered-select( name='card_expiration_year', autocomplete="cc-exp-year" )
- each year in yearRange
- option( value=year )!= year
-
-.card-security-code.credit-card-input-section
- label( for='card_security_code' ) Security Code
- input.bordered-input( type='tel', name='card_security_code', value=security_code, autocomplte="cc-csc", novalidate=true, pattern="\d*" )
+label Credit Card Number
+.credit-card-input-section
+ #card-element
diff --git a/src/mobile/components/layout/templates/mixpanel.html b/src/mobile/components/layout/templates/mixpanel.html
deleted file mode 100644
index b9f3537baaf..00000000000
--- a/src/mobile/components/layout/templates/mixpanel.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
\ No newline at end of file
diff --git a/src/mobile/components/layout/templates/quantcast.html b/src/mobile/components/layout/templates/quantcast.html
deleted file mode 100644
index 2c8488c0d3c..00000000000
--- a/src/mobile/components/layout/templates/quantcast.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/mobile/components/layout/templates/scaffold.jade b/src/mobile/components/layout/templates/scaffold.jade
index 641bf63545b..9dc03ebd08a 100644
--- a/src/mobile/components/layout/templates/scaffold.jade
+++ b/src/mobile/components/layout/templates/scaffold.jade
@@ -22,9 +22,8 @@ html( class=htmlClass )
analytics.load("#{sd.SEGMENT_WRITE_KEY}");
}}();
- //- Fonts + Mixpanel, Quantcast, Google analytics script
+ //- Fonts + Google analytics script
if sd.NODE_ENV != 'test'
- include ./quantcast.html
if sd.GOOGLE_ANALYTICS_ID
include ./ga.html
@@ -37,7 +36,7 @@ html( class=htmlClass )
script( src=asset('/assets/mobile_analytics.js'))
//- Stripe
- script( type="text/javascript", src="https://js.stripe.com/v2/" )
+ script( type="text/javascript", src="https://js.stripe.com/v3/" )
//- Include any scripts into the scripts block
block scripts
diff --git a/src/mobile/config.coffee b/src/mobile/config.coffee
index 78b843a293b..293ae4cbd2f 100644
--- a/src/mobile/config.coffee
+++ b/src/mobile/config.coffee
@@ -15,7 +15,6 @@ module.exports =
CLIENT_ID: 'e750db60ac506978fc70'
CLIENT_SECRET: '3a33d2085cbd1176153f99781bbce7c6'
COOKIE_DOMAIN: null
- CRITEO_ARTWORKS_ACCOUNT_NUMBER: 35250
CRITEO_AUCTIONS_ACCOUNT_NUMBER: 28539
DEFAULT_CACHE_TIME: 3600
DISABLE_IMAGE_PROXY: false
@@ -39,7 +38,6 @@ module.exports =
MAX_POLLS_FOR_MAX_BIDS: 20
MAX_SOCKETS: -1
METAPHYSICS_ENDPOINT: 'https://metaphysics-production.artsy.net'
- MIXPANEL_ID: null
NODE_ENV: 'development'
OPENREDIS_URL: null
PORT: 3003
diff --git a/src/mobile/index.js b/src/mobile/index.js
index 3a47f8e844a..2ef41f7719b 100644
--- a/src/mobile/index.js
+++ b/src/mobile/index.js
@@ -3,7 +3,12 @@ const app = (module.exports = require("express")())
// TODO: Move to src/lib/middleware/locals once done developing; this is just so
// we can get hot module reloading which only works in /desktop and /mobile
-app.use(require("@artsy/stitch/dist/server").middleware(modules))
+app.use(
+ require("@artsy/stitch/dist/server").middleware({
+ modules,
+ Wrapper: modules.StitchWrapper,
+ })
+)
app.use(require("./apps/auth"))
app.use(require("./apps/page"))
diff --git a/src/mobile/lib/global_client_setup.coffee b/src/mobile/lib/global_client_setup.coffee
index 4db9e35eb9e..5bbe0653c82 100644
--- a/src/mobile/lib/global_client_setup.coffee
+++ b/src/mobile/lib/global_client_setup.coffee
@@ -13,7 +13,8 @@ module.exports = ->
mountStitchBlocks = ->
{components, mountOnClient} = componentRenderer({
mode: 'client',
- modules: globalReactModules
+ modules: globalReactModules,
+ Wrapper: globalReactModules.StitchWrapper
})
sd.stitch.renderQueue.forEach (block) ->
diff --git a/src/mobile/lib/global_react_modules.js b/src/mobile/lib/global_react_modules.js
index 74202228763..96538e9195a 100644
--- a/src/mobile/lib/global_react_modules.js
+++ b/src/mobile/lib/global_react_modules.js
@@ -1,7 +1 @@
-export {
- ReactionArtworkDetails as ArtworkDetails,
-} from "desktop/components/react/stitch_components/ReactionArtworkDetails"
-
-export {
- ReactionArtworkArtistInfo as ArtworkArtistInfo,
-} from "desktop/components/react/stitch_components/ReactionArtworkArtistInfo"
+export * from "desktop/components/react/stitch_components"
diff --git a/src/mobile/models/fair.coffee b/src/mobile/models/fair.coffee
index c5488f623eb..90fb17d317e 100644
--- a/src/mobile/models/fair.coffee
+++ b/src/mobile/models/fair.coffee
@@ -139,10 +139,12 @@ module.exports = class Fair extends Backbone.Model
(not @related().profile.get('published'))
isNotOver: ->
- Date.parse(@get('end_at')) > new Date
+ not @isOver()
isOver: ->
- Date.parse(@get('end_at')) < new Date
+ endOfFair = moment.utc(@get('end_at')).endOf("day")
+ now = moment()
+ now.isAfter(endOfFair)
isCurrent: ->
@isEligible() and @isNotOver()
diff --git a/src/typings/express.d.ts b/src/typings/express.d.ts
new file mode 100644
index 00000000000..a7e9b64e29d
--- /dev/null
+++ b/src/typings/express.d.ts
@@ -0,0 +1,7 @@
+import * as express from "express"
+
+declare module "express" {
+ interface Request {
+ user?: any
+ }
+}
diff --git a/src/typings/global.d.ts b/src/typings/global.d.ts
new file mode 100644
index 00000000000..5adc4067f88
--- /dev/null
+++ b/src/typings/global.d.ts
@@ -0,0 +1,5 @@
+interface Window {
+ analytics?: {
+ page: (object, object) => void
+ }
+}
diff --git a/test.config.js b/test.config.js
index 915ce36a6f2..3c12ecd06ab 100644
--- a/test.config.js
+++ b/test.config.js
@@ -1,25 +1,25 @@
-require('@babel/register')({
- extensions: ['.ts', '.js', '.tsx', '.jsx'],
+require("@babel/register")({
+ extensions: [".ts", ".js", ".tsx", ".jsx"],
})
-require('coffeescript/register')
-require('@babel/polyfill')
-require('raf/polyfill')
-require('should')
-require('./src/lib/jade_hook')
+require("coffeescript/register")
+require("@babel/polyfill")
+require("raf/polyfill")
+require("should")
+require("./src/lib/jade_hook")
// FIXME: Do we need this?
// NOTE: Once we do AOT compilation we probably want to re-enable this on the server in development mode only.
// require('source-map-support/register')
-const path = require('path')
-const Adapter = require('enzyme-adapter-react-16')
-const Enzyme = require('enzyme')
-const sd = require('sharify').data
+const path = require("path")
+const Adapter = require("enzyme-adapter-react-16")
+const Enzyme = require("enzyme")
+const sd = require("sharify").data
// TODO: Look into why this bumps user off of other node command-line tab
-require('dotenv').config({
- path: path.join(process.cwd(), '.env.test'),
+require("dotenv").config({
+ path: path.join(process.cwd(), ".env.test"),
})
Enzyme.configure({
@@ -27,8 +27,8 @@ Enzyme.configure({
})
sd.AP = {
- loginPagePath: '/login',
- signupPagePath: '/signup',
- facebookPath: '/facebook',
- twitterPath: '/twitter',
+ loginPagePath: "/login",
+ signupPagePath: "/signup",
+ facebookPath: "/facebook",
+ twitterPath: "/twitter",
}
diff --git a/tsconfig.json b/tsconfig.json
index 6aff6ccd0b0..9ba9ecaa98d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,5 +17,5 @@
"reaction/*": ["../node_modules/@artsy/reaction/dist/*"]
}
},
- "include": ["./src"]
-}
\ No newline at end of file
+ "include": ["./src", "typings/*.d.ts"]
+}
diff --git a/yarn.lock b/yarn.lock
index 810a9023546..20741f0c841 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10,36 +10,31 @@
bindings "^1.3.0"
nan "^2.9.2"
-"@artsy/express-reloadable@^1.3.1":
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/@artsy/express-reloadable/-/express-reloadable-1.3.1.tgz#206adcc56ebcf999aece7efcc34eaf1460cf90a7"
- integrity sha1-IGrcxW68+Zmuzn78w06vFGDPkKc=
+"@artsy/detect-responsive-traits@^0.0.1":
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/@artsy/detect-responsive-traits/-/detect-responsive-traits-0.0.1.tgz#3d83384bf3323fbd4679a2d73155ab85dc73e850"
+ integrity sha512-jqrC40t1P6w9zIvsJJhWe8pxLWdEC/kJQmDc4/b3vAnGy1EsJpcIJGUys37kwut7tDYPiypUF06SImtZVLGQnQ==
+
+"@artsy/express-reloadable@1.4.0":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@artsy/express-reloadable/-/express-reloadable-1.4.0.tgz#71db6ca8ac274b2c7a2f38eb633794ce8f9e90fd"
+ integrity sha1-cdtsqKwnSyx6LzjrYzeUzo+ekP0=
dependencies:
chalk "^2.3.1"
chokidar "^1.7.0"
decache "^4.4.0"
-"@artsy/palette@^2.18.1":
- version "2.18.1"
- resolved "https://registry.yarnpkg.com/@artsy/palette/-/palette-2.18.1.tgz#876055f1cb85f32f18a1953aeef8a18aefee8bc6"
- integrity sha512-k3LGUBp4dX9ELFlL3T2+LyoDY6oFoYKZPmE5wIOGGQ+CCzq8BEwxpDzcTuV5HhUBFc8mCPGP+mIdXK/TiD6HLA==
- dependencies:
- rc-slider "^8.6.2"
- react "^16.5.0"
- styled-reset "^1.3.7"
- styled-system "^3.0.3"
-
-"@artsy/palette@^2.21.0":
- version "2.21.0"
- resolved "https://registry.yarnpkg.com/@artsy/palette/-/palette-2.21.0.tgz#3187ad4c277e444ca8dbaf7b1c47cc3e8ca3ebb0"
- integrity sha512-me1hTzFkoJxQUuy8rmI0zzRArhbqSOfjb8jgRQTrTaZ2D52vJYWJ8T++obhplCzGFq1KxYwFZWEA/rW8iwHUBQ==
+"@artsy/palette@2.23.2":
+ version "2.23.2"
+ resolved "https://registry.yarnpkg.com/@artsy/palette/-/palette-2.23.2.tgz#7c96deffb8691958f772133c18b233da62f6679e"
+ integrity sha512-3R9EtI26qkpNPhMSRimFPQzfbNZVJv6YyhI7Ivtm94zEyr/I5sL7oBg47G9RYYmib8DEC1dSYzWflNI4J1NnHw==
dependencies:
rc-slider "^8.6.2"
react "^16.5.0"
react-spring "^5.7.2"
styled-system "^3.1.11"
-"@artsy/passport@^1.1.0":
+"@artsy/passport@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@artsy/passport/-/passport-1.1.0.tgz#06120530d7891de0e4b2c8d8163bb088dddce4c2"
integrity sha512-hGcgTVk3P8rIF2kJ0P/1lC47AxhlvJBnUlbzbw7hK6bd+hYUD0o4qAzEd+mp1H+a329ofrxL8xu2mUqJKyIRtQ==
@@ -58,20 +53,21 @@
superagent "^1.2.0"
underscore.string "^3.2.2"
-"@artsy/react-responsive-media@^1.0.12":
- version "1.0.12"
- resolved "https://registry.yarnpkg.com/@artsy/react-responsive-media/-/react-responsive-media-1.0.12.tgz#3a76be54e82d1d658ee1794ecb692ea64468314c"
- integrity sha512-BU7HUAVBvCjc3H7s117d+FL6Ufodc2hwgQZ2HuPq23jEXSYR6PHS98Kqd0vMthUeI4IdUY4Yc0du75Qu30OLew==
+"@artsy/react-responsive-media@^2.0.0-beta.5":
+ version "2.0.0-beta.5"
+ resolved "https://registry.yarnpkg.com/@artsy/react-responsive-media/-/react-responsive-media-2.0.0-beta.5.tgz#d61e1a9f215d38d90ec2bb97dc1ff7409d0346fa"
+ integrity sha512-XRYA77v/j3mVInwy5EYb8NtmMkkAD1/XDxDi45BO0oduv4hsljJfjtjK7jN0ziJ6JUm2QTx/t6QwuaT9E7vTuA==
-"@artsy/reaction@^6.1.8":
- version "6.1.8"
- resolved "https://registry.yarnpkg.com/@artsy/reaction/-/reaction-6.1.8.tgz#c4153066a12faa72e3402c250bb19f4465094cb2"
- integrity sha512-dfN3cCY7G7OiS+yUYiaEekptdYoC4o4UIP1R4bp3nyM1+s4IdsdV+2uohJr4PVV/BBdFOUG2PnP5xfWlqCNWQQ==
+"@artsy/reaction@9.1.12":
+ version "9.1.12"
+ resolved "https://registry.yarnpkg.com/@artsy/reaction/-/reaction-9.1.12.tgz#006f0a9c34b8e075baf42392e883f777d795fec5"
+ integrity sha512-jnRLlaJT6T2FMHag3YbxthDtjWc7UlQhn1HdE/dZKUrkrayeG6wCTt0l0FfG6GXxYeRZA9ch0FacgDhL/lT2xQ==
dependencies:
- "@artsy/palette" "^2.21.0"
- "@artsy/react-responsive-media" "^1.0.12"
+ "@artsy/detect-responsive-traits" "^0.0.1"
+ "@artsy/react-responsive-media" "^2.0.0-beta.5"
"@sentry/browser" "^4.2.3"
cheerio "^1.0.0-rc.2"
+ currency.js "^1.2.1"
farce "^0.2.6"
formik "^0.11.11"
found "^0.3.14"
@@ -82,6 +78,7 @@
jsonp "^0.2.1"
loadable-components "^2.2.2"
lodash "^4.17.4"
+ memoize-one "^4.0.3"
moment-timezone "^0.5.13"
numeral "^2.0.4"
openseadragon "^2.3.1"
@@ -97,8 +94,8 @@
react-oembed-container "^0.3.0"
react-overlays "^0.8.3"
react-relay "https://github.com/alloy/relay/releases/download/v1.5.0-artsy.3/react-relay-1.5.0-artsy.3.tgz"
- react-relay-network-modern "^2.3.1"
- react-relay-network-modern-ssr "^1.1.2"
+ react-relay-network-modern "^2.4.0"
+ react-relay-network-modern-ssr "^1.2.2"
react-responsive-decorator "^0.0.1"
react-router "^4.2.0"
react-sizeme "^2.4.4"
@@ -118,15 +115,16 @@
styled-system "^3.1.11"
superagent "^3.6.3"
trunc-html "^1.1.2"
+ underscore.string "^3.3.5"
unstated "^2.1.1"
unstated-debug "^0.2.0"
url "^0.11.0"
yup "^0.24.1"
-"@artsy/stitch@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@artsy/stitch/-/stitch-2.0.0.tgz#c0a44186b3eac779bd3c7a6b0030c7ad7acff754"
- integrity sha512-7k5wf7+5lE57aVF0Ep5QyVEQSEYHdLHIuTJxz5syWEq6C+F5m45x4nqKBz+ZmpU8P5oZkvFv2TbEH0DMVXYOGQ==
+"@artsy/stitch@3.1.0":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@artsy/stitch/-/stitch-3.1.0.tgz#6ea39eced27a8323c760f328fa966a0e7442bef1"
+ integrity sha512-uTgB9wnmgDUsN1DZLZqqiBibTMJbf96VjY//xG038/iEuoGbvzE+fAL7ZSv1AK3QmIagp/UXLW7x+h72tc1knw==
dependencies:
consolidate "^0.14.5"
lodash "^4.17.4"
@@ -867,9 +865,9 @@
regenerator-runtime "^0.12.0"
"@babel/runtime@^7.1.2":
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.2.tgz#81c89935f4647706fc54541145e6b4ecfef4b8e3"
- integrity sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg==
+ version "7.1.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.5.tgz#4170907641cf1f61508f563ece3725150cc6fe39"
+ integrity sha512-xKnPpXG/pvK1B90JkwwxSGii90rQGKtzcMt2gI5G6+M0REXaq6rOHsGC2ay6/d0Uje7zzvSzjEzfR3ENhFlrfA==
dependencies:
regenerator-runtime "^0.12.0"
@@ -1068,9 +1066,9 @@
integrity sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==
"@types/node@*":
- version "10.12.0"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.0.tgz#ea6dcbddbc5b584c83f06c60e82736d8fbb0c235"
- integrity sha512-3TUHC3jsBAB7qVRGxT6lWyYo2v96BMmD2PTcl47H25Lu7UXtFH/2qqmKiVrnel6Ne//0TFYf6uvNX+HW2FRkLQ==
+ version "10.12.7"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.7.tgz#195808b2d4b2e7c33e75e7d9b24aeee88f94660d"
+ integrity sha512-Zh5Z4kACfbeE8aAOYh9mqotRxaZMro8MbBQtR8vEXOMiZo2rGEh2LayJijKdlu48YnS6y2EFU/oo2NCe5P6jGw==
"@types/node@^6.0.46":
version "6.0.78"
@@ -1142,6 +1140,11 @@
dependencies:
source-map "^0.6.1"
+"@types/webpack-env@^1.13.6":
+ version "1.13.6"
+ resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.6.tgz#128d1685a7c34d31ed17010fc87d6a12c1de6976"
+ integrity sha512-5Th3OsZ4gTRdr9Mho83BQ23cex4sRhOR4XTG+m+cJc0FhtUBK9Vn62hBJ+pnQYnSxoPOsKoAPOx6FcphxBC8ng==
+
"@types/webpack@^4.4.11":
version "4.4.11"
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.4.11.tgz#0ca832870d55c4e92498c01d22d00d02b0f62ae9"
@@ -1613,6 +1616,7 @@ antigravity@artsy/antigravity:
version "0.1.3"
resolved "https://codeload.github.com/artsy/antigravity/tar.gz/a4438d2fe9d0cdf71f1c47faba371cd3d004e140"
dependencies:
+ coffeescript "1.11.1"
express "*"
any-observable@^0.2.0:
@@ -2720,11 +2724,6 @@ binary-extensions@^1.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
integrity sha1-SOyNFt9Dd+rl+liEaCSAr02Vx3Q=
-bindings@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
- integrity sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=
-
bindings@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7"
@@ -2773,10 +2772,29 @@ bluebird@^3.1.1, bluebird@^3.5.1:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==
-blueimp-file-upload@9.9.0:
- version "9.9.0"
- resolved "https://registry.yarnpkg.com/blueimp-file-upload/-/blueimp-file-upload-9.9.0.tgz#316f1f710b92f2a5be4f079cf50937dfb2de6ab5"
- integrity sha1-MW8fcQuS8qW+Twec9Qk337LearU=
+blueimp-canvas-to-blob@3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.5.0.tgz#5679ac32f6a2835821f0c3ad661719ff85a9236b"
+ integrity sha1-VnmsMvaig1gh8MOtZhcZ/4WpI2s=
+
+blueimp-file-upload@9.22.1:
+ version "9.22.1"
+ resolved "https://registry.yarnpkg.com/blueimp-file-upload/-/blueimp-file-upload-9.22.1.tgz#08a9fccbaf1ec930acf6242c217620b057f0ecc6"
+ integrity sha512-ezGkn/agWUWZOw8mYa5yYC9LvUlrT5bN3zk2fPlpLWgyhbBMz8BSGKO3M48BWlXWAeR+lVtEhy9xiG8FLnHEVw==
+ optionalDependencies:
+ blueimp-canvas-to-blob "3.5.0"
+ blueimp-load-image "2.12.2"
+ blueimp-tmpl "3.6.0"
+
+blueimp-load-image@2.12.2:
+ version "2.12.2"
+ resolved "https://registry.yarnpkg.com/blueimp-load-image/-/blueimp-load-image-2.12.2.tgz#6a17598aab858d4fbf01543e0631141b51057c87"
+ integrity sha1-ahdZiquFjU+/AVQ+BjEUG1EFfIc=
+
+blueimp-tmpl@3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/blueimp-tmpl/-/blueimp-tmpl-3.6.0.tgz#a4910975d042e2bc03ba77f0e62d04f1548a524c"
+ integrity sha1-pJEJddBC4rwDunfw5i0E8VSKUkw=
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.6"
@@ -3434,6 +3452,11 @@ class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+ dependencies:
+ arr-union "^3.1.0"
+ define-property "^0.2.5"
+ isobject "^3.0.0"
+ static-extend "^0.1.1"
classnames@^2.2.5:
version "2.2.5"
@@ -4175,9 +4198,9 @@ csrf@~3.0.3:
uid-safe "2.1.4"
css-animation@^1.3.2:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.4.1.tgz#5b8813125de0fbbbb0bbe1b472ae84221469b7a8"
- integrity sha1-W4gTEl3g+7uwu+G0cq6EIhRpt6g=
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.5.0.tgz#c96b9097a5ef74a7be8480b45cc44e4ec6ca2bf5"
+ integrity sha512-hWYoWiOZ7Vr20etzLh3kpWgtC454tW5vn4I6rLANDgpzNSkO7UfOqyCEeaoBSG9CYWQpRkFWTWbWW8o3uZrNLw==
dependencies:
babel-runtime "6.x"
component-classes "^1.2.5"
@@ -4269,6 +4292,11 @@ csurf@^1.8.3:
csrf "~3.0.3"
http-errors "~1.5.0"
+currency.js@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/currency.js/-/currency.js-1.2.1.tgz#18d42ac74d833795051f4a310c83f041013a882f"
+ integrity sha512-7t0jYDZeQYCcaxpgwNOiBz8GaG/qdqTdo+kcTYgCuCNx1p2jLMpJt8h34TJ5INtN9jhryAiLK/atmjwUf13t4A==
+
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -4375,8 +4403,6 @@ dd-trace@artsy/dd-trace-js#artsy:
semver "^5.5.0"
shimmer "^1.2.0"
url-parse "^1.4.3"
- optionalDependencies:
- "@airbnb/node-memwatch" "^1.0.2"
debounce@~1.0.0:
version "1.0.2"
@@ -4785,9 +4811,11 @@ dom-align@^1.7.0:
integrity sha512-B85D4ef2Gj5lw0rK0KM2+D5/pH7yqNxg2mB+E8uzFaolpm7RQmsxEfjyEuNiF8UBBkffumYDeKRzTzc3LePP+w==
dom-helpers@^3.2.1, dom-helpers@^3.3.1:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
- integrity sha512-2Sm+JaYn74OiTM2wHvxJOo3roiq/h25Yi69Fqk269cNUwIXsCvATB6CRSFC9Am/20G2b28hGv/+7NiWydIrPvg==
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
+ integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
@@ -4956,7 +4984,16 @@ electron-to-chromium@^1.3.62:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.63.tgz#6485f5f4f3375358aa8fa23c2029ada208483b8d"
integrity sha512-Ec35NNY040HKuSxMAzBMgz/uUI78amSWpBUD9x2gN7R7gkb/wgAcClngWklcLP0/lm/g0UUYHnC/tUIlZj8UvQ==
-electron@1.7.8, electron@^1.4.4:
+electron@1.7.16:
+ version "1.7.16"
+ resolved "https://registry.yarnpkg.com/electron/-/electron-1.7.16.tgz#40e6b5553e3a87ce7ea52eb05f7926bc40cab11c"
+ integrity sha512-k17+2K3hny6g1etWMkWvzEL06yapZGpqG66O3e5vxfzeHT3FgqrNa3xRF7znjaqvWQmmEdGFdSktQADjUZ0gog==
+ dependencies:
+ "@types/node" "^7.0.18"
+ electron-download "^3.0.1"
+ extract-zip "^1.0.3"
+
+electron@^1.4.4:
version "1.7.8"
resolved "https://registry.yarnpkg.com/electron/-/electron-1.7.8.tgz#27b791a6895171a7d52991b99442cdbd10a3539d"
integrity sha1-J7eRpolRcafVKZG5lELNvRCjU50=
@@ -7212,10 +7249,10 @@ hoist-non-react-statics@^2.5.0:
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==
-hoist-non-react-statics@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.0.1.tgz#fba3e7df0210eb9447757ca1a7cb607162f0a364"
- integrity sha512-1kXwPsOi0OGQIZNVMPvgWJ9tSnGMiMfJdihqEzrPEXlHOBh9AAHXX/QYmAJTXztnz/K+PQ8ryCb4eGaN6HlGbQ==
+hoist-non-react-statics@^3.0.1, hoist-non-react-statics@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.1.0.tgz#42414ccdfff019cd2168168be998c7b3bd5245c0"
+ integrity sha512-MYcYuROh7SBM69xHGqXEwQqDux34s9tz+sCnxJmN18kgWh6JFdTw/5YdZtqsOdZJXddE/wUpCzfEdDrJj8p0Iw==
dependencies:
react-is "^16.3.2"
@@ -8601,7 +8638,7 @@ jest-worker@^23.2.0:
dependencies:
merge-stream "^1.0.1"
-jest@^23.5.2:
+jest@^23.6.0:
version "23.6.0"
resolved "https://registry.yarnpkg.com/jest/-/jest-23.6.0.tgz#ad5835e923ebf6e19e7a1d7529a432edfee7813d"
integrity sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw==
@@ -9342,11 +9379,6 @@ lodash-es@^4.17.3, lodash-es@^4.2.0, lodash-es@^4.2.1:
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
integrity sha1-3MHXVS4VCgZABzupyzHXDwMpUOc=
-lodash-es@^4.17.5:
- version "4.17.11"
- resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.11.tgz#145ab4a7ac5c5e52a3531fb4f310255a152b4be0"
- integrity sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q==
-
lodash._baseassign@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
@@ -9791,6 +9823,11 @@ memfs-or-file-map-to-github-branch@^1.1.0:
resolved "https://registry.yarnpkg.com/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.1.2.tgz#9d46c02481b7eca8e5ee8a94f170b7e0138cad67"
integrity sha512-D2JKK2DTuVYQqquBWco3K6UfSVyVwmd58dgNqh+TgxHOZdTmR8I130gjMbVCkemDl/EzqDA62417cJxKL3/FFA==
+memoize-one@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.0.3.tgz#cdfdd942853f1a1b4c71c5336b8c49da0bf0273c"
+ integrity sha512-QmpUu4KqDmX0plH4u+tf0riMc1KHE1+lw95cMrLlXQAFOx/xnBtwhZ52XJxd9X2O6kwKBqX32kmhbhlobD0cuw==
+
memory-fs@^0.4.0, memory-fs@~0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@@ -9799,14 +9836,6 @@ memory-fs@^0.4.0, memory-fs@~0.4.1:
errno "^0.1.3"
readable-stream "^2.0.1"
-memwatch-ng@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/memwatch-ng/-/memwatch-ng-1.2.0.tgz#b5a457a7c46b1db813b45a11ccfe09e8bd7fccfa"
- integrity sha1-taRXp8RrHbgTtFoRzP4J6L1/zPo=
- dependencies:
- bindings "^1.2.1"
- nan "^2.3.2"
-
meow@^3.1.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
@@ -10132,9 +10161,9 @@ module-details-from-path@^1.0.3:
integrity sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=
moment-timezone@^0.5.13:
- version "0.5.21"
- resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.21.tgz#3cba247d84492174dbf71de2a9848fa13207b845"
- integrity sha512-j96bAh4otsgj3lKydm3K7kdtA3iKf2m6MY2iSYCzCm5a1zmHo1g+aK3068dDEeocLZQIS9kU8bsdQHLqEvgW0A==
+ version "0.5.23"
+ resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.23.tgz#7cbb00db2c14c71b19303cb47b0fb0a6d8651463"
+ integrity sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w==
dependencies:
moment ">= 2.9.0"
@@ -10235,7 +10264,7 @@ mute-stream@0.0.7, mute-stream@~0.0.4:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
-nan@^2.3.0, nan@^2.3.2:
+nan@^2.3.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
integrity sha1-5P805slf37WuzAjeZZb0NgWn20U=
@@ -11470,9 +11499,9 @@ prettier@^1.10.2:
integrity sha512-TcdNoQIWFoHblurqqU6d1ysopjq7UX0oRcT/hJ8qvBAELiYWn+Ugf0AXdnzISEJ7vuhNnQ98N8jR8Sh53x4IZg==
prettier@^1.14.3:
- version "1.14.3"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895"
- integrity sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg==
+ version "1.15.2"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.2.tgz#d31abe22afa4351efa14c7f8b94b58bb7452205e"
+ integrity sha512-YgPLFFA0CdKL4Eg2IHtUSjzj/BWgszDHiNQAe0VAIBse34148whfdzLagRL+QiKS+YfK5ftB6X4v/MBw8yCoug==
pretty-bytes@^1.0.2:
version "1.0.4"
@@ -12202,9 +12231,9 @@ react-dom@^16.5.0:
schedule "^0.3.0"
react-head@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/react-head/-/react-head-3.0.1.tgz#c7a3583c77328b9a5f9172100f8446f4b4778f05"
- integrity sha512-GTblZjkKp17JhPKJWeK1Ogu2KXL+xVKB/+riYch97UiIfesP+/f4qexF+qb6a+KyiZJz2Sn+quHJRna2SoPToA==
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/react-head/-/react-head-3.0.2.tgz#efe79b1e5805a18a5ffc58e6a810eeeb609d82bd"
+ integrity sha512-+wtK+pbxl17GfiBgqaSMrRob2rQZ0UJnRb1iEVzWQPUGC/TNMUTmpIzKx55xVKXbfsNTk8QAq0p3139YEnisUA==
dependencies:
"@babel/runtime" "^7.0.0"
tiny-invariant "^1.0.0"
@@ -12233,10 +12262,10 @@ react-is@^16.3.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22"
integrity sha512-ybEM7YOr4yBgFd6w8dJqwxegqZGJNBZl6U27HnGKuTZmDvVrD5quWOK/wAnMywiZzW+Qsk+l4X2c70+thp/A8Q==
-react-is@^16.3.2:
- version "16.6.0"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.0.tgz#456645144581a6e99f6816ae2bd24ee94bdd0c01"
- integrity sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g==
+react-is@^16.3.2, react-is@^16.6.0:
+ version "16.6.3"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.3.tgz#d2d7462fcfcbe6ec0da56ad69047e47e56e7eac0"
+ integrity sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA==
react-is@^16.4.2:
version "16.4.2"
@@ -12251,7 +12280,7 @@ react-lazy-load-image-component@^1.1.1:
lodash.debounce "^4.0.8"
lodash.throttle "^4.1.1"
-react-lifecycles-compat@^3.0.4:
+react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
@@ -12302,23 +12331,24 @@ react-redux@^5.0.2:
prop-types "^15.5.10"
react-redux@^5.0.7:
- version "5.0.7"
- resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8"
- integrity sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.1.tgz#88e368682c7fa80e34e055cd7ac56f5936b0f52f"
+ integrity sha512-LE7Ned+cv5qe7tMV5BPYkGQ5Lpg8gzgItK07c67yHvJ8t0iaD9kPFPAli/mYkiyJYrs2pJgExR2ZgsGqlrOApg==
dependencies:
- hoist-non-react-statics "^2.5.0"
- invariant "^2.0.0"
- lodash "^4.17.5"
- lodash-es "^4.17.5"
+ "@babel/runtime" "^7.1.2"
+ hoist-non-react-statics "^3.1.0"
+ invariant "^2.2.4"
loose-envify "^1.1.0"
- prop-types "^15.6.0"
+ prop-types "^15.6.1"
+ react-is "^16.6.0"
+ react-lifecycles-compat "^3.0.0"
-react-relay-network-modern-ssr@^1.1.2:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/react-relay-network-modern-ssr/-/react-relay-network-modern-ssr-1.2.1.tgz#3cb0391f9827c78b5f9bf6dff021d9f1bb4a3351"
- integrity sha512-Y2erct+4h6qt9FdB/0sdieLC582l5w1KBgtsSQHIHqz5n7RrFNAcJRSrnUGQT/+NC2jMqvE/ud34DaRSrbi8ng==
+react-relay-network-modern-ssr@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/react-relay-network-modern-ssr/-/react-relay-network-modern-ssr-1.2.2.tgz#9f611872113cc91839600939b0d4edf97a4f8adc"
+ integrity sha512-35SHsvHS6IhZ7Sh9qXwjMhC5nZHhv5P9ERS5oti9u/B6GsQEC3cTwVCeSKIJNs+SxWkwQ6Z7DmzhPMWu1sNI0Q==
-react-relay-network-modern@^2.3.1:
+react-relay-network-modern@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/react-relay-network-modern/-/react-relay-network-modern-2.4.0.tgz#639ea0745545ab148d0c78714330e93dca7e031c"
integrity sha512-LR/RhHcJclDCVEiwRhlRtf1iltSnbGSxS2rag+bAljMFJ0kOVSYUK3+NDPRbcHLRqbha1FuQXBVfHjjPE6jhMA==
@@ -14350,12 +14380,7 @@ styled-components@^3.4.5:
stylis-rule-sheet "^0.0.10"
supports-color "^3.2.3"
-styled-reset@^1.3.7:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/styled-reset/-/styled-reset-1.6.0.tgz#d10a0d419cd4d3163f324615554fdee7e13b5c47"
- integrity sha512-UI+qgAaEPp7tPksAWn5voIoiefGq63jPaIdOBvcxNDwc4ZrEwfmwQMjExrmiJTL0EpsRGJ3nOhS0x7Kkqu5nUg==
-
-styled-system@^3.0.3, styled-system@^3.1.11:
+styled-system@^3.1.11:
version "3.1.11"
resolved "https://registry.yarnpkg.com/styled-system/-/styled-system-3.1.11.tgz#a91a38cf7a0f0e625b897a04fdd506a359a3629f"
integrity sha512-d0p32F7Y55uRWNDb1P0JcIiGVi13ZxiSCvn8zNS68exAKW9Q5jp+IGTXUIavQOD/J8r3tydtE3vRk8Ii2i39HA==
@@ -14768,9 +14793,9 @@ timespan@~2.3.0:
integrity sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=
tiny-invariant@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.1.tgz#54700d039a0384ef2e83afd0e81af84c6d67b140"
- integrity sha512-avcKCNM2yJqD33H/WJLgIu3QNRXFOjARGJSdLi8IpKESCyhm67vyPWTRjnIbX2uI/pn52tqYcao333R3PBVhbQ==
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.3.tgz#91efaaa0269ccb6271f0296aeedb05fc3e067b7a"
+ integrity sha512-ytQx8T4DL8PjlX53yYzcIC0WhIZbpR0p1qcYjw2pHu3w6UtgWwFJQ/02cnhOnBBhlFx/edUIfcagCaQSe3KMWg==
tmp@^0.0.29:
version "0.0.29"
@@ -15121,7 +15146,12 @@ ua-parser-js@^0.7.12:
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
integrity sha1-BMgamb3V3FImPqKdJMa/jUgYpLs=
-ua-parser-js@^0.7.18, ua-parser-js@^0.7.9:
+ua-parser-js@^0.7.18:
+ version "0.7.19"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b"
+ integrity sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==
+
+ua-parser-js@^0.7.9:
version "0.7.18"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"
integrity sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA==
@@ -15216,6 +15246,14 @@ underscore.string@^3.2.2:
sprintf-js "^1.0.3"
util-deprecate "^1.0.2"
+underscore.string@^3.3.5:
+ version "3.3.5"
+ resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023"
+ integrity sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==
+ dependencies:
+ sprintf-js "^1.0.3"
+ util-deprecate "^1.0.2"
+
underscore.string@~2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b"
@@ -15506,7 +15544,7 @@ uuid@3.0.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728"
integrity sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=
-uuid@^3.0.0, uuid@^3.1.0:
+uuid@^3.0.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.0.tgz#b237147804881d7b86f40a7ff8f590f15c37de32"
integrity sha512-ijO9N2xY/YaOqQ5yz5c4sy2ZjWmA6AR6zASb/gdpeKZ8+948CxwfMW9RrKVk5may6ev8c0/Xguu32e2Llelpqw==
@@ -15516,7 +15554,7 @@ uuid@^3.0.1:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
integrity sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=
-uuid@^3.3.2:
+uuid@^3.1.0, uuid@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==