diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index 998b053143f..a89dd9e82cf 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -22,7 +22,6 @@ const { CI, CMS_URL, ENABLE_SIGN_IN_WITH_APPLE, - EXPERIMENTAL_APP_SHELL, FACEBOOK_APP_NAMESPACE, PREDICTION_URL, FORCE_CLOUDFRONT_URL, @@ -56,7 +55,6 @@ const sharifyPath = sharify({ CDN_URL, CMS_URL, ENABLE_SIGN_IN_WITH_APPLE, - EXPERIMENTAL_APP_SHELL, FACEBOOK_APP_NAMESPACE, FORCE_CLOUDFRONT_URL, GEMINI_CLOUDFRONT_URL, diff --git a/cypress/integration/partnerProfile.spec.js b/cypress/integration/partnerProfile.spec.js index 23e0a8caa74..837a74e2cf3 100644 --- a/cypress/integration/partnerProfile.spec.js +++ b/cypress/integration/partnerProfile.spec.js @@ -46,6 +46,7 @@ describe("/:partner_id", () => { }) it("shows partner articles", () => { cy.visit("gagosian-gallery/articles") + cy.wait(2000) cy.contains("Articles") }) diff --git a/jest.config.js b/jest.config.js index 9df50df3479..6f7bdef2d3d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,9 +1,10 @@ const sharedConfig = { transform: { + "\\.(gql|graphql)$": "jest-transform-graphql", "^.+\\.coffee$": "/node_modules/jest-coffee-preprocessor/index.js", ".(ts|tsx|js|jsx)": "babel-jest", - "\\.graphql$": "jest-raw-loader", }, + cacheDirectory: ".cache/jest", coverageDirectory: "./coverage/", collectCoverage: true, coverageReporters: ["lcov", "text-summary"], diff --git a/package.json b/package.json index f30bded14e2..8f14b7daee7 100644 --- a/package.json +++ b/package.json @@ -328,6 +328,7 @@ "fork-ts-checker-notifier-webpack-plugin": "0.4.0", "fork-ts-checker-webpack-plugin": "0.4.10", "friendly-errors-webpack-plugin": "1.6.1", + "graphql-tag": "^2.10.3", "graphql-tools": "4.0.3", "hulk-editor": "craigspaeth/hulk", "husky": "3.0.5", @@ -337,8 +338,8 @@ "jest": "24.9.0", "jest-coffee-preprocessor": "1.0.0", "jest-junit": "6.4.0", - "jest-raw-loader": "1.0.1", "jest-styled-components": "7.0.0-2", + "jest-transform-graphql": "^2.1.0", "jsdom": "11.6.2", "jsdom-global": "3.0.2", "json-loader": "0.5.7", diff --git a/src/desktop/analytics/inquiry_questionnaire.js b/src/desktop/analytics/inquiry_questionnaire.js index 03283569f81..1f33e254bdb 100644 --- a/src/desktop/analytics/inquiry_questionnaire.js +++ b/src/desktop/analytics/inquiry_questionnaire.js @@ -17,18 +17,15 @@ const analytics = window.analytics function getTrackingOptions() { var trackingOptions = {} - // FIXME: Remove once A/B test completes - if (sd.CLIENT_NAVIGATION_V5 === "experiment") { - const referrer = window.analytics.__artsyReferrer - // Grab referrer from our trackingMiddleware in Reaction, since we're in a - // single-page-app context and the value will need to be refreshed on route - // change. See: https://github.com/artsy/reaction/blob/master/src/Artsy/Analytics/trackingMiddleware.ts - if (referrer) { - trackingOptions = { - page: { - referrer, - }, - } + const referrer = window.analytics.__artsyReferrer + // Grab referrer from our trackingMiddleware in Reaction, since we're in a + // single-page-app context and the value will need to be refreshed on route + // change. See: https://github.com/artsy/reaction/blob/master/src/Artsy/Analytics/trackingMiddleware.ts + if (referrer) { + trackingOptions = { + page: { + referrer, + }, } } @@ -57,12 +54,7 @@ const analytics = window.analytics // _per session_, and therefore can't rely on `once`, as subsequent // inquiries would then not get tracked as there's no "hard jumps" // between pages. See: https://github.com/artsy/force/pull/5232 - // FIXME: Remove once A/B test completes - if (window.sd.CLIENT_NAVIGATION_V5 === "experiment") { - analyticsHooks.on(namespace(name), handler) - } else { - analyticsHooks.once(namespace(name), handler) - } + analyticsHooks.on(namespace(name), handler) } // DOM events diff --git a/src/desktop/analytics/main_layout.js b/src/desktop/analytics/main_layout.js index cbdf21084ca..7c60ac58e7c 100644 --- a/src/desktop/analytics/main_layout.js +++ b/src/desktop/analytics/main_layout.js @@ -90,18 +90,15 @@ class PageTimeTracker { this.timer = setTimeout(() => { let trackingOptions = {} - // FIXME: Remove once A/B test completes - if (sd.CLIENT_NAVIGATION_V5 === "experiment") { - const referrer = window.analytics.__artsyReferrer - // Grab referrer from our trackingMiddleware in Reaction, since we're in a - // single-page-app context and the value will need to be refreshed on route - // change. See: https://github.com/artsy/reaction/blob/master/src/Artsy/Analytics/trackingMiddleware.ts - if (referrer) { - trackingOptions = { - page: { - referrer, - }, - } + const referrer = window.analytics.__artsyReferrer + // Grab referrer from our trackingMiddleware in Reaction, since we're in a + // single-page-app context and the value will need to be refreshed on route + // change. See: https://github.com/artsy/reaction/blob/master/src/Artsy/Analytics/trackingMiddleware.ts + if (referrer) { + trackingOptions = { + page: { + referrer, + }, } } diff --git a/src/desktop/apps/artist/client.tsx b/src/desktop/apps/artist/client.tsx deleted file mode 100644 index b4c2b8923fc..00000000000 --- a/src/desktop/apps/artist/client.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/client" -import { data as sd } from "sharify" -import { routes } from "v2/Apps/Artist/routes" -import React from "react" -import ReactDOM from "react-dom" -import { setupArtistSignUpModal } from "desktop/apps/artist/components/cta" -import { loadableReady } from "@loadable/component" - -const mediator = require("desktop/lib/mediator.coffee") - -buildClientApp({ - routes, - context: { - user: sd.CURRENT_USER, - mediator, - } as any, -}) - .then(({ ClientApp }) => { - loadableReady(() => { - ReactDOM.hydrate( - , - document.getElementById("react-root"), - () => { - setupArtistSignUpModal() - } - ) - }) - }) - .catch(error => { - console.error(error) - }) - -if (module.hot) { - module.hot.accept() -} diff --git a/src/desktop/apps/artist/server.tsx b/src/desktop/apps/artist/server.tsx deleted file mode 100644 index 9b199053a2a..00000000000 --- a/src/desktop/apps/artist/server.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { buildServerApp } from "v2/Artsy/Router/server" -import { stitch } from "@artsy/stitch" -import { routes } from "v2/Apps/Artist/routes" -import React from "react" -import { buildServerAppContext } from "desktop/lib/buildServerAppContext" -import express, { Request, Response, NextFunction } from "express" -import { skipIfClientSideRoutingEnabled } from "desktop/components/split_test/skipIfClientSideRoutingEnabled" - -export const app = express() - -app.get( - "/artist/:artistID*", - skipIfClientSideRoutingEnabled, - async (req: Request, res: Response, next: NextFunction) => { - try { - const user = req.user && req.user.toJSON() - - const context = buildServerAppContext(req, res, {}) - const { - bodyHTML, - redirect, - status, - headTags, - styleTags, - scripts, - } = await buildServerApp({ - routes, - url: req.url, - userAgent: req.header("User-Agent"), - context, - }) - - if (redirect) { - res.redirect(302, redirect.url) - return - } - - const { APP_URL, IS_MOBILE, REFERRER } = res.locals.sd - const isExternalReferer = !(REFERRER && REFERRER.includes(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", - blocks: { - head: () => {headTags}, - body: bodyHTML, - }, - locals: { - ...res.locals, - assetPackage: "artist", - scripts, - styleTags, - }, - }) - - res.locals.PAGE_CACHE = { status, key: req.url, html: layout } - - res.status(status).send(layout) - } catch (error) { - next(error) - } - } -) diff --git a/src/desktop/apps/experimental-app-shell/apps/artist/__tests__/artistMiddleware.jest.ts b/src/desktop/apps/artsy-v2/apps/artist/__tests__/artistMiddleware.jest.ts similarity index 100% rename from src/desktop/apps/experimental-app-shell/apps/artist/__tests__/artistMiddleware.jest.ts rename to src/desktop/apps/artsy-v2/apps/artist/__tests__/artistMiddleware.jest.ts diff --git a/src/desktop/apps/artsy-v2/apps/artist/artistClient.tsx b/src/desktop/apps/artsy-v2/apps/artist/artistClient.tsx new file mode 100644 index 00000000000..6d30f97ea40 --- /dev/null +++ b/src/desktop/apps/artsy-v2/apps/artist/artistClient.tsx @@ -0,0 +1,5 @@ +import { setupArtistSignUpModal } from "desktop/components/artistSignupModal/artistSignupModal" + +export const artistClient = () => { + setupArtistSignUpModal() +} diff --git a/src/desktop/apps/experimental-app-shell/apps/artist/artistMiddleware.tsx b/src/desktop/apps/artsy-v2/apps/artist/artistMiddleware.tsx similarity index 100% rename from src/desktop/apps/experimental-app-shell/apps/artist/artistMiddleware.tsx rename to src/desktop/apps/artsy-v2/apps/artist/artistMiddleware.tsx diff --git a/src/desktop/apps/experimental-app-shell/apps/artwork/__tests__/artworkMiddleware.jest.ts b/src/desktop/apps/artsy-v2/apps/artwork/__tests__/artworkMiddleware.jest.ts similarity index 100% rename from src/desktop/apps/experimental-app-shell/apps/artwork/__tests__/artworkMiddleware.jest.ts rename to src/desktop/apps/artsy-v2/apps/artwork/__tests__/artworkMiddleware.jest.ts diff --git a/src/desktop/apps/experimental-app-shell/apps/artwork/artworkClient.tsx b/src/desktop/apps/artsy-v2/apps/artwork/artworkClient.tsx similarity index 97% rename from src/desktop/apps/experimental-app-shell/apps/artwork/artworkClient.tsx rename to src/desktop/apps/artsy-v2/apps/artwork/artworkClient.tsx index 7f4ab5503d4..5a86e08df63 100644 --- a/src/desktop/apps/experimental-app-shell/apps/artwork/artworkClient.tsx +++ b/src/desktop/apps/artsy-v2/apps/artwork/artworkClient.tsx @@ -7,7 +7,7 @@ export const artworkClient = () => { 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/buyers_premium/index.coffee") + const openAuctionBuyerPremium = require("desktop/components/artworkBuyersPremium/index.coffee") const ViewInRoomView = require("desktop/components/view_in_room/view.coffee") const $ = require("jquery") const mediator = require("desktop/lib/mediator.coffee") diff --git a/src/desktop/apps/experimental-app-shell/apps/artwork/artworkMiddleware.tsx b/src/desktop/apps/artsy-v2/apps/artwork/artworkMiddleware.tsx similarity index 87% rename from src/desktop/apps/experimental-app-shell/apps/artwork/artworkMiddleware.tsx rename to src/desktop/apps/artsy-v2/apps/artwork/artworkMiddleware.tsx index e55120885f5..3efff4779b8 100644 --- a/src/desktop/apps/experimental-app-shell/apps/artwork/artworkMiddleware.tsx +++ b/src/desktop/apps/artsy-v2/apps/artwork/artworkMiddleware.tsx @@ -13,12 +13,7 @@ export const handleArtworkImageDownload = async (req, res, next) => { if (req.user) { imageRequest.set("X-ACCESS-TOKEN", req.user.get("accessToken")) } - req - .pipe( - imageRequest, - { end: false } - ) - .pipe(res) + req.pipe(imageRequest, { end: false }).pipe(res) } else { const error: any = new Error("Not authorized to download this image.") error.status = 403 diff --git a/src/desktop/apps/experimental-app-shell/apps/search/__tests__/searchMiddleware.jest.ts b/src/desktop/apps/artsy-v2/apps/search/__tests__/searchMiddleware.jest.ts similarity index 100% rename from src/desktop/apps/experimental-app-shell/apps/search/__tests__/searchMiddleware.jest.ts rename to src/desktop/apps/artsy-v2/apps/search/__tests__/searchMiddleware.jest.ts diff --git a/src/desktop/apps/experimental-app-shell/apps/search/searchMiddleware.tsx b/src/desktop/apps/artsy-v2/apps/search/searchMiddleware.tsx similarity index 94% rename from src/desktop/apps/experimental-app-shell/apps/search/searchMiddleware.tsx rename to src/desktop/apps/artsy-v2/apps/search/searchMiddleware.tsx index 99f1d2994bb..c1d28b52193 100644 --- a/src/desktop/apps/experimental-app-shell/apps/search/searchMiddleware.tsx +++ b/src/desktop/apps/artsy-v2/apps/search/searchMiddleware.tsx @@ -30,8 +30,7 @@ export const searchMiddleware = async (req, res, next) => { const layout = await stitch({ basePath: __dirname, - layout: - "../../../../components/main_layout/templates/experimental_app_shell.jade", + layout: "../../../../components/main_layout/templates/artsy_v2.jade", blocks: { loadingComponent: _props => { return ( diff --git a/src/desktop/apps/experimental-app-shell/client.tsx b/src/desktop/apps/artsy-v2/client.tsx similarity index 97% rename from src/desktop/apps/experimental-app-shell/client.tsx rename to src/desktop/apps/artsy-v2/client.tsx index 3935df32b3d..e69530762cd 100644 --- a/src/desktop/apps/experimental-app-shell/client.tsx +++ b/src/desktop/apps/artsy-v2/client.tsx @@ -12,7 +12,6 @@ const mediator = require("desktop/lib/mediator.coffee") buildClientApp({ routes: getAppRoutes(), context: { - EXPERIMENTAL_APP_SHELL: true, user: sd.CURRENT_USER, mediator, } as any, diff --git a/src/desktop/apps/experimental-app-shell/middleware/__tests__/userRequiredMiddleware.jest.ts b/src/desktop/apps/artsy-v2/middleware/__tests__/userRequiredMiddleware.jest.ts similarity index 100% rename from src/desktop/apps/experimental-app-shell/middleware/__tests__/userRequiredMiddleware.jest.ts rename to src/desktop/apps/artsy-v2/middleware/__tests__/userRequiredMiddleware.jest.ts diff --git a/src/desktop/apps/experimental-app-shell/middleware/userRequiredMiddleware.tsx b/src/desktop/apps/artsy-v2/middleware/userRequiredMiddleware.tsx similarity index 100% rename from src/desktop/apps/experimental-app-shell/middleware/userRequiredMiddleware.tsx rename to src/desktop/apps/artsy-v2/middleware/userRequiredMiddleware.tsx diff --git a/src/desktop/apps/experimental-app-shell/server.tsx b/src/desktop/apps/artsy-v2/server.tsx similarity index 87% rename from src/desktop/apps/experimental-app-shell/server.tsx rename to src/desktop/apps/artsy-v2/server.tsx index 5b68db7125b..2118912cc3f 100644 --- a/src/desktop/apps/experimental-app-shell/server.tsx +++ b/src/desktop/apps/artsy-v2/server.tsx @@ -22,15 +22,6 @@ app.get("/artwork/:artworkID/download/:filename", handleArtworkImageDownload) */ app.get( "/*", - (_req, res, next) => { - const isExperiment = res.locals.sd.CLIENT_NAVIGATION_V5 === "experiment" - - if (!isExperiment) { - return next("route") - } - return next() - }, - userRequiredMiddleware, /** @@ -58,9 +49,7 @@ app.get( bodyHTML, headTags, } = await buildServerApp({ - context: buildServerAppContext(req, res, { - EXPERIMENTAL_APP_SHELL: true, - }), + context: buildServerAppContext(req, res), routes: getAppRoutes(), url: req.url, userAgent: req.header("User-Agent"), @@ -77,8 +66,7 @@ app.get( const layout = await stitch({ basePath: __dirname, - layout: - "../../components/main_layout/templates/experimental_app_shell.jade", + layout: "../../components/main_layout/templates/artsy_v2.jade", blocks: { body: bodyHTML, head: () => <>{headTags}, diff --git a/src/desktop/apps/experimental-app-shell/utils/__tests__/getPageType.jest.ts b/src/desktop/apps/artsy-v2/utils/__tests__/getPageType.jest.ts similarity index 100% rename from src/desktop/apps/experimental-app-shell/utils/__tests__/getPageType.jest.ts rename to src/desktop/apps/artsy-v2/utils/__tests__/getPageType.jest.ts diff --git a/src/desktop/apps/experimental-app-shell/utils/getPageType.ts b/src/desktop/apps/artsy-v2/utils/getPageType.ts similarity index 100% rename from src/desktop/apps/experimental-app-shell/utils/getPageType.ts rename to src/desktop/apps/artsy-v2/utils/getPageType.ts diff --git a/src/desktop/apps/artwork/__tests__/client.jest.ts b/src/desktop/apps/artwork/__tests__/client.jest.ts deleted file mode 100644 index 2a70251c582..00000000000 --- a/src/desktop/apps/artwork/__tests__/client.jest.ts +++ /dev/null @@ -1,111 +0,0 @@ -import Backbone from "backbone" -const mediator = require("desktop/lib/mediator.coffee") - -jest.mock("react-dom", () => ({ - hydrate: jest.fn(), -})) -jest.mock("desktop/components/inquiry_questionnaire/index.coffee", () => - jest.fn() -) - -jest.mock("desktop/components/cookies/index.coffee", () => ({ - get: jest.fn(), - expire: jest.fn(), - set: jest.fn(), -})) -const mockCookies = require("desktop/components/cookies/index.coffee") - .get as jest.Mock - -const inquiryMock = require("desktop/components/inquiry_questionnaire/index.coffee") -const mediatorTriggerMock = jest.spyOn(mediator, "trigger") - -require("../client") - -describe("artwork client", () => { - Backbone.sync = jest.fn() - document.getElementById = jest.fn() - - beforeEach(() => { - mockCookies.mockClear() - mediatorTriggerMock.mockClear() - inquiryMock.mockClear() - Backbone.sync.mockImplementation(() => Promise.resolve()) - }) - - describe("Launch inquiry", () => { - describe("Contact gallery", () => { - it("launchInquiryFlow does not trigger auth modal", async () => { - await mediator.trigger("launchInquiryFlow", { - artworkId: "chip-hughes-stripes", - }) - expect(mediatorTriggerMock).toBeCalledTimes(1) - expect(mediatorTriggerMock).toBeCalledWith("launchInquiryFlow", { - artworkId: "chip-hughes-stripes", - }) - }) - - it("launchInquiryFlow triggers inquiry modal", async () => { - await mediator.trigger("launchInquiryFlow", { - artworkId: "chip-hughes-stripes", - }) - expect(Backbone.sync).toBeCalled() - expect(inquiryMock.mock.calls[0][0].artwork.get("id")).toBe( - "chip-hughes-stripes" - ) - expect(inquiryMock.mock.calls[0][0].ask_specialist).toBeFalsy() - }) - }) - - describe("Ask a specialist", () => { - it("openBuyNowAskSpecialistModal does not trigger auth modal", async () => { - await mediator.trigger("openBuyNowAskSpecialistModal", { - artworkId: "chip-hughes-stripes", - }) - expect(mediatorTriggerMock).toBeCalledTimes(1) - expect(mediatorTriggerMock).toBeCalledWith( - "openBuyNowAskSpecialistModal", - { - artworkId: "chip-hughes-stripes", - } - ) - }) - - it("openBuyNowAskSpecialistModal triggers inquiry modal", async () => { - await mediator.trigger("openBuyNowAskSpecialistModal", { - artworkId: "chip-hughes-stripes", - }) - expect(Backbone.sync).toBeCalled() - expect(inquiryMock.mock.calls[0][0].artwork.get("id")).toBe( - "chip-hughes-stripes" - ) - expect(inquiryMock.mock.calls[0][0].ask_specialist).toBeTruthy() - }) - }) - - describe("Ask an auction specialist", () => { - it("openAuctionAskSpecialistModal does not trigger auth modal", async () => { - await mediator.trigger("openAuctionAskSpecialistModal", { - artworkId: "chip-hughes-stripes", - }) - expect(mediatorTriggerMock).toBeCalledTimes(1) - expect(mediatorTriggerMock).toBeCalledWith( - "openAuctionAskSpecialistModal", - { - artworkId: "chip-hughes-stripes", - } - ) - }) - - it("openAuctionAskSpecialistModal triggers inquiry modal", async () => { - await mediator.trigger("openAuctionAskSpecialistModal", { - artworkId: "chip-hughes-stripes", - }) - expect(Backbone.sync).toBeCalled() - expect(inquiryMock.mock.calls[0][0].artwork.get("id")).toBe( - "chip-hughes-stripes" - ) - expect(inquiryMock.mock.calls[0][0].ask_specialist).toBeTruthy() - }) - }) - }) -}) diff --git a/src/desktop/apps/artwork/__tests__/routes.jest.ts b/src/desktop/apps/artwork/__tests__/routes.jest.ts deleted file mode 100644 index 31992729f5e..00000000000 --- a/src/desktop/apps/artwork/__tests__/routes.jest.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { handleDownload } from "../server" - -const Artwork = require("desktop/models/artwork.coffee") - -jest.mock("superagent", () => { - return { - get: () => { - return { set: jest.fn() } - }, - } -}) - -jest.mock("desktop/models/artwork.coffee") - -describe("Request handler for download artwork route", () => { - let req - let res - let next - const pipeMock = jest.fn() - - describe("/artwork/:artworkID/download/:filename", () => { - beforeEach(() => { - req = { - params: { artworkID: "percy-painting" }, - user: { get: () => "token" }, - pipe: () => { - return { pipe: pipeMock } - }, - } - - next = jest.fn() - }) - - it("serves a 403", done => { - Artwork.mockImplementation(() => { - return { - isDownloadable: () => { - return false - }, - fetch: () => jest.fn(), - } - }) - handleDownload(req, res, next).then(() => { - expect(next).toHaveBeenCalledWith( - expect.objectContaining({ - message: "Not authorized to download this image.", - status: 403, - }) - ) - done() - }) - }) - - it("pipes the image when the request is authorized", done => { - Artwork.mockImplementation(() => { - return { - isDownloadable: () => { - return true - }, - fetch: () => jest.fn(), - downloadableUrl: () => jest.fn(), - } - }) - handleDownload(req, res, next).then(() => { - expect(pipeMock).toHaveBeenCalled() - done() - }) - }) - }) -}) diff --git a/src/desktop/apps/artwork/client.tsx b/src/desktop/apps/artwork/client.tsx deleted file mode 100644 index f3ad86ba881..00000000000 --- a/src/desktop/apps/artwork/client.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/client" -import { routes } from "v2/Apps/Artwork/routes" -import { data as sd } from "sharify" -import React from "react" -import ReactDOM from "react-dom" -import { enableIntercom } from "lib/intercom" -import { recordArtworkView } from "lib/components/record_artwork_view" -import { loadableReady } from "@loadable/component" - -const $ = require("jquery") -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/buyers_premium/index.coffee") -const ViewInRoomView = require("desktop/components/view_in_room/view.coffee") - -buildClientApp({ - routes, - context: { - user: sd.CURRENT_USER, - mediator, - }, -}) - .then(({ ClientApp }) => { - loadableReady(() => { - ReactDOM.hydrate(, document.getElementById("react-root")) - }) - }) - .catch(error => { - console.error(error) - }) - -if (module.hot) { - module.hot.accept() -} - -const artworkSlug = location.pathname.replace(/\/artwork\//, "") -recordArtworkView(artworkSlug, sd.CURRENT_USER) - -const openInquireableModal = ( - artworkId: string, - { ask_specialist }, - artworkOptions = {} -) => { - if (!artworkId) return - const user = User.instantiate() - const inquiry = new ArtworkInquiry({ notification_delay: 600 }) - const artwork = new Artwork({ id: artworkId }) - - // TODO: Look into why this is needed. - $.ajaxSettings.headers = { - "X-XAPP-TOKEN": sd.ARTSY_XAPP_TOKEN, - "X-ACCESS-TOKEN": - sd.CURRENT_USER != null ? sd.CURRENT_USER.accessToken : undefined, - } - artwork.fetch().then(() => { - artwork.set(artworkOptions) - 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 => { - openInquireableModal( - options.artworkId, - { ask_specialist: true }, - { is_in_auction: true } - ) -}) - -mediator.on("openViewInRoom", options => { - try { - const { dimensions } = options - const { url, width, height } = options.image - - let newWidth = width - let newHeight = height - - const bounds = document - .querySelector("[data-is-default=true]") - .getBoundingClientRect() - - const imgRatio = newWidth / newHeight - const boundsRatio = bounds.width / bounds.height - - if (boundsRatio > imgRatio) { - newHeight = bounds.height - newWidth = (newHeight * width) / height - } else if (boundsRatio < imgRatio) { - newWidth = bounds.width - newHeight = (height * newWidth) / width - } else { - newWidth = bounds.width - newHeight = newWidth - } - - const newLeft = (bounds.width - newWidth) / 2 + bounds.left - const newTop = bounds.top + Math.abs(bounds.height - newHeight) / 2 - - const positionStyles = { - position: "absolute", - top: `${newTop}px`, - left: `${newLeft}px`, - width: `${newWidth}px`, - height: `${newHeight}px`, - } - - const viewInRoom = new ViewInRoomView({ - imgSelector: "[data-type=artwork-image]", - imgUrl: url, - positionStyles: positionStyles, - dimensions: dimensions.cm, - }) - - $("body").prepend(viewInRoom.render().$el) - } catch { - // TODO: Add some proper error handling - } -}) - -mediator.on("openAuctionBuyerPremium", options => { - openAuctionBuyerPremium(options.auctionId) -}) - -mediator.on("enableIntercomForBuyers", options => { - enableIntercom(options) -}) diff --git a/src/desktop/apps/artwork/server.tsx b/src/desktop/apps/artwork/server.tsx deleted file mode 100644 index 7d57eac3e34..00000000000 --- a/src/desktop/apps/artwork/server.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from "react" -import { buildServerApp } from "v2/Artsy/Router/server" -import { routes } from "v2/Apps/Artwork/routes" -import { stitch } from "@artsy/stitch" -import { buildServerAppContext } from "desktop/lib/buildServerAppContext" -import express, { Request, Response, NextFunction } from "express" -import request from "superagent" -import { skipIfClientSideRoutingEnabled } from "desktop/components/split_test/skipIfClientSideRoutingEnabled" - -const Artwork = require("desktop/models/artwork.coffee") - -export const app = express() - -export const handleDownload = async ( - req: Request, - res: Response, - next: NextFunction -) => { - const artwork = new Artwork({ id: req.params.artworkID }) - await artwork.fetch({ - cache: true, - }) - - if (artwork.isDownloadable(req.user)) { - const imageRequest = request.get(artwork.downloadableUrl(req.user)) - if (req.user) { - imageRequest.set("X-ACCESS-TOKEN", req.user.get("accessToken")) - } - req.pipe(imageRequest, { end: false }).pipe(res) - } else { - const error: any = new Error("Not authorized to download this image.") - error.status = 403 - next(error) - } -} - -app.get("/artwork/:artworkID/download/:filename", handleDownload) - -app.get( - "/artwork/:artworkID*", - skipIfClientSideRoutingEnabled, - async (req: Request, res: Response, next: NextFunction) => { - const { GOOGLE_ADWORDS_ID } = res.locals.sd - - const context = buildServerAppContext(req, res, { - googleAdId: GOOGLE_ADWORDS_ID, - }) - - try { - const { - bodyHTML, - redirect, - status, - headTags, - styleTags, - scripts, - } = await buildServerApp({ - routes, - url: req.url, - userAgent: req.header("User-Agent"), - context, - }) - - if (redirect) { - res.redirect(302, redirect.url) - return - } - - const layout = await stitch({ - basePath: __dirname, - layout: "../../components/main_layout/templates/react_redesign.jade", - blocks: { - head: () => {headTags}, - body: bodyHTML, - }, - locals: { - ...res.locals, - assetPackage: "artwork", - scripts, - styleTags, - }, - }) - - res.status(status).send(layout) - } catch (error) { - next(error) - } - } -) diff --git a/src/desktop/apps/auction_support/index.coffee b/src/desktop/apps/auction_support/index.coffee index fbe0f3dcdc8..4e98482430c 100644 --- a/src/desktop/apps/auction_support/index.coffee +++ b/src/desktop/apps/auction_support/index.coffee @@ -1,6 +1,5 @@ express = require 'express' routes = require './routes' -{ skipIfClientSideRoutingEnabled } = require("../../components/split_test/skipIfClientSideRoutingEnabled") app = module.exports = express() app.set 'views', __dirname + '/templates' diff --git a/src/desktop/apps/collect/client.js b/src/desktop/apps/collect/client.js deleted file mode 100644 index 8a9976069f3..00000000000 --- a/src/desktop/apps/collect/client.js +++ /dev/null @@ -1,27 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/buildClientApp" -import { data as sd } from "sharify" -import { collectRoutes } from "v2/Apps/Collect/collectRoutes" -import mediator from "desktop/lib/mediator.coffee" -import React from "react" -import ReactDOM from "react-dom" -import { loadableReady } from "@loadable/component" - -buildClientApp({ - routes: collectRoutes, - context: { - user: sd.CURRENT_USER, - mediator, - }, -}) - .then(({ ClientApp }) => { - loadableReady(() => { - ReactDOM.hydrate(, document.getElementById("react-root")) - }) - }) - .catch(error => { - console.error(error) - }) - -if (module.hot) { - module.hot.accept() -} diff --git a/src/desktop/apps/collect/fixtures/categories.json b/src/desktop/apps/collect/fixtures/categories.json deleted file mode 100644 index 99df17770f8..00000000000 --- a/src/desktop/apps/collect/fixtures/categories.json +++ /dev/null @@ -1,460 +0,0 @@ -{ - "global": [ - { - "id": "abstract-art", - "name": "Abstract", - "image": "images/abstract.jpg" - }, - { - "id": "animals", - "name": "Animals", - "image": "images/animals.jpg" - }, - { - "id": "art-and-technology", - "name": "Technology", - "image": "images/technology.jpg" - }, - { - "id": "figurative-art", - "name": "Figurative", - "image": "images/figurative.jpg" - }, - { - "id": "gender", - "name": "Gender & Sexuality", - "image": "images/gender.jpg" - }, - { - "id": "geometric", - "name": "Geometric", - "image": "images/geometric.jpg" - }, - { - "id": "landscapes-and-waterscapes", - "name": "Landscape", - "image": "images/landscape.jpg" - }, - { - "id": "pop-and-contemporary-pop", - "name": "Pop", - "image": "images/pop.jpg" - }, - { - "id": "portrait", - "name": "Portraiture", - "image": "images/portrait.jpg" - }, - { - "id": "still-life", - "name": "Still Life", - "image": "images/stilllife.jpg" - } - ], - "photography": [ - { - "id": "abstract-art", - "name": "Abstract" - }, - { - "id": "fashion-photography", - "name": "Fashion" - }, - { - "id": "architecture-in-art", - "name": "Architecture" - }, - { - "id": "black-and-white", - "name": "Black" - }, - { - "id": "celebrity", - "name": "Celebrity" - }, - { - "id": "emerging-art", - "name": "Emerging" - }, - { - "id": "landscapes-and-waterscapes", - "name": "Landscape" - }, - { - "id": "modern-photography", - "name": "Modern Photography" - }, - { - "id": "portrait", - "name": "Portraiture" - }, - { - "id": "topographic-photography", - "name": "Topographic" - } - ], - "sculpture": [ - { - "id": "abstract-art", - "name": "Abstract", - "image": "images/abstract.jpg" - }, - { - "id": "traditional-arts-of-africa-oceania-and-the-americas", - "name": "Tribal Art", - "image": "images/abstract.jpg" - }, - { - "id": "biomorphic", - "name": "Biomorphic", - "image": "images/abstract.jpg" - }, - { - "id": "ceramic", - "name": "Ceramics", - "image": "images/abstract.jpg" - }, - { - "id": "emerging-art", - "name": "Emerging Artists", - "image": "images/abstract.jpg" - }, - { - "id": "found-objects-and-common-materials", - "name": "Found & Common Materials", - "image": "images/abstract.jpg" - }, - { - "id": "installation", - "name": "Installation Art", - "image": "images/abstract.jpg" - }, - { - "id": "light-art", - "name": "Light Art", - "image": "images/abstract.jpg" - }, - { - "id": "minimalism-and-contemporary-minimalist", - "name": "Minimalist", - "image": "images/abstract.jpg" - }, - { - "id": "textile-arts", - "name": "Textile Arts", - "image": "images/abstract.jpg" - } - ], - "prints": [ - { - "id": "artists-books", - "name": "Artists’ Books", - "image": "images/abstract.jpg" - }, - { - "id": "pop-and-contemporary-pop", - "name": "Pop", - "image": "images/abstract.jpg" - }, - { - "id": "emerging-art", - "name": "Emerging", - "image": "images/abstract.jpg" - }, - { - "id": "etching-slash-engraving", - "name": "Etchings & Intaglio", - "image": "images/abstract.jpg" - }, - { - "id": "geometric-abstraction", - "name": "Geometric", - "image": "images/abstract.jpg" - }, - { - "id": "lithograph-1", - "name": "Lithographs", - "image": "images/abstract.jpg" - }, - { - "id": "modern-and-impressionist-prints", - "name": "Modern & Impressionist", - "image": "images/abstract.jpg" - }, - { - "id": "silkscreen-1", - "name": "Silkscreen", - "image": "images/abstract.jpg" - }, - { - "id": "ukiyo-e", - "name": "Japanese Woodblock", - "image": "images/abstract.jpg" - }, - { - "id": "woodcut-and-linocut", - "name": "Woodcut & Linocut", - "image": "images/abstract.jpg" - } - ], - "work-on-paper": [ - { - "id": "abstract-art", - "name": "Abstract", - "image": "images/abstract.jpg" - }, - { - "id": "black-and-white", - "name": "Black & White", - "image": "images/abstract.jpg" - }, - { - "id": "collage", - "name": "Collage", - "image": "images/abstract.jpg" - }, - { - "id": "pop-and-contemporary-pop", - "name": "Pop", - "image": "images/abstract.jpg" - }, - { - "id": "drawing", - "name": "Drawing", - "image": "images/abstract.jpg" - }, - { - "id": "emerging-art", - "name": "Emerging Artists", - "image": "images/abstract.jpg" - }, - { - "id": "human-figure", - "name": "Human Figure", - "image": "images/abstract.jpg" - }, - { - "id": "modern-slash-impressionist-art", - "name": "Modern & Impressionist", - "image": "images/abstract.jpg" - }, - { - "id": "pastel", - "name": "Pastels", - "image": "images/abstract.jpg" - }, - { - "id": "watercolor", - "name": "Watercolors", - "image": "images/abstract.jpg" - } - ], - "film-slash-video": [ - { - "id": "animation", - "name": "Animation", - "image": "images/abstract.jpg" - }, - { - "id": "cinematic", - "name": "Cinematic", - "image": "images/abstract.jpg" - }, - { - "id": "contemporary-conceptualism", - "name": "Conceptual", - "image": "images/abstract.jpg" - }, - { - "id": "cultural-commentary", - "name": "Cultural Commentary", - "image": "images/abstract.jpg" - }, - { - "id": "digital-art", - "name": "Digital Art", - "image": "images/abstract.jpg" - }, - { - "id": "feminist-art-and-contemporary-feminist", - "name": "Feminist", - "image": "images/abstract.jpg" - }, - { - "id": "installation", - "name": "Installation Art", - "image": "images/abstract.jpg" - }, - { - "id": "interactive", - "name": "Interactive", - "image": "images/abstract.jpg" - }, - { - "id": "performance-art", - "name": "Performance", - "image": "images/abstract.jpg" - }, - { - "id": "post-internet-art", - "name": "Post-Internet", - "image": "images/abstract.jpg" - } - ], - "design": [ - { - "id": "20th-century-art", - "name": "20th Century", - "image": "images/abstract.jpg" - }, - { - "id": "ceramic", - "name": "Ceramics", - "image": "images/abstract.jpg" - }, - { - "id": "contemporary-design", - "name": "Contemporary", - "image": "images/abstract.jpg" - }, - { - "id": "emerging-design", - "name": "Emerging Designers", - "image": "images/abstract.jpg" - }, - { - "id": "furniture", - "name": "Furniture", - "image": "images/abstract.jpg" - }, - { - "id": "glass-objects", - "name": "Glass Objects", - "image": "images/abstract.jpg" - }, - { - "id": "lighting", - "name": "Lighting", - "image": "images/abstract.jpg" - }, - { - "id": "seating", - "name": "Seating", - "image": "images/abstract.jpg" - }, - { - "id": "table", - "name": "Tables", - "image": "images/abstract.jpg" - }, - { - "id": "textile-arts", - "name": "Textiles", - "image": "images/abstract.jpg" - } - ], - "jewelry": [ - { - "id": "brooches", - "name": "Brooches", - "image": "images/abstract.jpg" - }, - { - "id": "contemporary-jewelry", - "name": "Contemporary", - "image": "images/abstract.jpg" - }, - { - "id": "gemstone", - "name": "Gemstones", - "image": "images/abstract.jpg" - }, - { - "id": "geometric", - "name": "Geometric", - "image": "images/abstract.jpg" - }, - { - "id": "gold", - "name": "Gold", - "image": "images/abstract.jpg" - }, - { - "id": "jewelry-by-painters-and-sculptors", - "name": "Artist Jewelry", - "image": "images/abstract.jpg" - }, - { - "id": "modern-jewelry", - "name": "Modern", - "image": "images/abstract.jpg" - }, - { - "id": "necklaces", - "name": "Necklaces", - "image": "images/abstract.jpg" - }, - { - "id": "rings", - "name": "Rings", - "image": "images/abstract.jpg" - }, - { - "id": "silver", - "name": "Silver", - "image": "images/abstract.jpg" - } - ], - "painting": [ - { - "id": "abstract-art", - "name": "Abstract Art", - "image": "images/abstract.jpg" - }, - { - "id": "pop-and-contemporary-pop", - "name": "Pop", - "image": "images/abstract.jpg" - }, - { - "id": "gemstone", - "name": "Emerging Painters", - "image": "images/abstract.jpg" - }, - { - "id": "figurative-painting", - "name": "Figurative", - "image": "images/abstract.jpg" - }, - { - "id": "graffiti-slash-street-art", - "name": "Street Art", - "image": "images/abstract.jpg" - }, - { - "id": "hyperrealism", - "name": "Hyperrealism", - "image": "images/abstract.jpg" - }, - { - "id": "east-asian-ink-and-wash-painting", - "name": "Ink & Wash", - "image": "images/abstract.jpg" - }, - { - "id": "landscapes-and-waterscapes", - "name": "Landscape", - "image": "images/abstract.jpg" - }, - { - "id": "portrait", - "name": "Portait", - "image": "images/abstract.jpg" - }, - { - "id": "still-life", - "name": "Still Life", - "image": "images/abstract.jpg" - } - ] -} diff --git a/src/desktop/apps/collect/meta.tsx b/src/desktop/apps/collect/meta.tsx deleted file mode 100644 index 0a4caec03af..00000000000 --- a/src/desktop/apps/collect/meta.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React, { Fragment } from "react" - -interface Props { - appUrl: string - headTags: JSX.Element[] -} - -export const Meta = (props: Props) => { - const { headTags } = props - - return ( - - {headTags} - - - - - ) -} diff --git a/src/desktop/apps/collect/server.tsx b/src/desktop/apps/collect/server.tsx deleted file mode 100644 index 73669e44af7..00000000000 --- a/src/desktop/apps/collect/server.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { buildServerApp } from "v2/Artsy/Router/buildServerApp" -import { stitch } from "@artsy/stitch" -import { collectRoutes } from "v2/Apps/Collect/collectRoutes" -import express from "express" -import React from "react" -import { Meta } from "./meta" -import { buildServerAppContext } from "desktop/lib/buildServerAppContext" -import { skipIfClientSideRoutingEnabled } from "desktop/components/split_test/skipIfClientSideRoutingEnabled" - -export const app = express() - -const index = async (req, res, next) => { - try { - const { APP_URL, IS_MOBILE } = res.locals.sd - - const { - headTags, - bodyHTML, - redirect, - scripts, - styleTags, - status, - } = await buildServerApp({ - routes: collectRoutes, - url: req.url, - userAgent: req.header("User-Agent"), - context: buildServerAppContext(req, res), - }) - - if (redirect) { - res.redirect(302, redirect.url) - return - } - - // Render layout - const layout = await stitch({ - basePath: __dirname, - layout: "../../components/main_layout/templates/react_redesign.jade", - blocks: { - head: () => , - body: bodyHTML, - }, - locals: { - ...res.locals, - assetPackage: "collect", - bodyClass: IS_MOBILE ? "body-header-fixed body-no-margins" : null, - scripts, - styleTags, - }, - }) - - res.locals.PAGE_CACHE = { status, key: req.url, html: layout } - res.send(layout) - } catch (error) { - console.log(error) - next(error) - } -} - -app.get("/collect", skipIfClientSideRoutingEnabled, index) -app.get("/collect/:medium?", skipIfClientSideRoutingEnabled, index) -app.get("/collection/:slug", skipIfClientSideRoutingEnabled, index) -app.get("/collections", skipIfClientSideRoutingEnabled, index) diff --git a/src/desktop/apps/conversations/client.tsx b/src/desktop/apps/conversations/client.tsx deleted file mode 100644 index 454d52f6dfd..00000000000 --- a/src/desktop/apps/conversations/client.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/client" -import { data as sd } from "sharify" -import { conversationRoutes } from "v2/Apps/Conversation/routes" -import React from "react" -import ReactDOM from "react-dom" -import { loadableReady } from "@loadable/component" - -const mediator = require("desktop/lib/mediator.coffee") - -buildClientApp({ - routes: conversationRoutes, - context: { - user: sd.CURRENT_USER, - mediator, - } as any, -}) - .then(({ ClientApp }) => { - loadableReady(() => { - ReactDOM.hydrate(, document.getElementById("react-root")) - }) - }) - .catch(error => { - console.error(error) - }) - -if (module.hot) { - module.hot.accept() -} diff --git a/src/desktop/apps/conversations/server.tsx b/src/desktop/apps/conversations/server.tsx deleted file mode 100644 index 46bf050b532..00000000000 --- a/src/desktop/apps/conversations/server.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { buildServerApp } from "v2/Artsy/Router/server" -import { stitch } from "@artsy/stitch" -import { conversationRoutes } from "v2/Apps/Conversation/routes" -import React from "react" -import { buildServerAppContext } from "desktop/lib/buildServerAppContext" -import express, { Request, Response, NextFunction } from "express" - -export const app = express() - -app.get( - "/user/conversations*", - async (req: Request, res: Response, next: NextFunction) => { - try { - const { - bodyHTML, - redirect, - status, - headTags, - styleTags, - scripts, - } = await buildServerApp({ - context: buildServerAppContext(req, res), - routes: conversationRoutes, - url: req.url, - userAgent: req.header("User-Agent"), - }) - - if (redirect) { - res.redirect(302, redirect.url) - return - } - - // Render layout - const layout = await stitch({ - basePath: __dirname, - layout: "../../components/main_layout/templates/react_redesign.jade", - blocks: { - head: () => {headTags}, - body: bodyHTML, - }, - locals: { - ...res.locals, - assetPackage: "conversations", - scripts, - styleTags, - }, - }) - - res.status(status).send(layout) - } catch (error) { - next(error) - } - } -) diff --git a/src/desktop/apps/experimental-app-shell/apps/artist/artistClient.tsx b/src/desktop/apps/experimental-app-shell/apps/artist/artistClient.tsx deleted file mode 100644 index 8324165ae52..00000000000 --- a/src/desktop/apps/experimental-app-shell/apps/artist/artistClient.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { setupArtistSignUpModal } from "desktop/apps/artist/components/cta" - -export const artistClient = () => { - setupArtistSignUpModal() -} diff --git a/src/desktop/apps/identity_verification/client.tsx b/src/desktop/apps/identity_verification/client.tsx deleted file mode 100644 index 7ab066cdace..00000000000 --- a/src/desktop/apps/identity_verification/client.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/client" -import { data as sd } from "sharify" -import { loadableReady } from "@loadable/component" - -import { routes } from "v2/Apps/IdentityVerification/routes" -import React from "react" -import ReactDOM from "react-dom" - -buildClientApp({ - routes, - context: { - user: sd.CURRENT_USER, - }, -}) - .then(({ ClientApp }) => { - loadableReady(() => { - ReactDOM.hydrate(, document.getElementById("react-root")) - }) - }) - .catch(error => { - console.error(error) - }) - -if (module.hot) { - module.hot.accept() -} diff --git a/src/desktop/apps/identity_verification/routes.tsx b/src/desktop/apps/identity_verification/routes.tsx deleted file mode 100644 index 4f9150d5156..00000000000 --- a/src/desktop/apps/identity_verification/routes.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { buildServerApp } from "v2/Artsy/Router/server" -import { buildServerAppContext } from "desktop/lib/buildServerAppContext" -import { routes } from "v2/Apps/IdentityVerification/routes" -import { stitch } from "@artsy/stitch" - -export const identityVerification = async (req, res, next) => { - if (!res.locals.sd.CURRENT_USER) { - return res.redirect( - `/login?redirectTo=${encodeURIComponent(req.originalUrl)}` - ) - } - try { - const { - bodyHTML, - redirect, - status, - headTags, - scripts, - styleTags, - } = await buildServerApp({ - routes, - url: req.url, - userAgent: req.header("User-Agent"), - context: buildServerAppContext(req, res), - }) - - if (redirect) { - res.redirect(302, redirect.url) - return - } - - // Render layout - const layout = await stitch({ - basePath: __dirname, - layout: "../../components/main_layout/templates/react_redesign.jade", - blocks: { - head: () => headTags, - body: bodyHTML, - }, - locals: { - ...res.locals, - assetPackage: "identity_verification", - scripts, - styleTags, - }, - }) - - res.status(status).send(layout) - } catch (error) { - next(error) - } -} diff --git a/src/desktop/apps/identity_verification/server.ts b/src/desktop/apps/identity_verification/server.ts deleted file mode 100644 index e9a2a0c7c26..00000000000 --- a/src/desktop/apps/identity_verification/server.ts +++ /dev/null @@ -1,11 +0,0 @@ -import express from "express" -import { skipIfClientSideRoutingEnabled } from "desktop/components/split_test/skipIfClientSideRoutingEnabled" -import { identityVerification } from "desktop/apps/identity_verification/routes" - -export const app = express() - -app.get( - "/identity-verification/:id", - skipIfClientSideRoutingEnabled, - identityVerification -) diff --git a/src/desktop/apps/order/__tests__/routes.jest.js b/src/desktop/apps/order/__tests__/routes.jest.js deleted file mode 100644 index e1d7f26af06..00000000000 --- a/src/desktop/apps/order/__tests__/routes.jest.js +++ /dev/null @@ -1,85 +0,0 @@ -import { stitch } from "@artsy/stitch" -import { buildServerApp } from "v2/Artsy/Router/server" -import { checkoutFlow } from "../routes" - -jest.mock("@artsy/stitch", () => ({ - stitch: jest.fn(), -})) - -jest.mock("v2/Artsy/Router/server", () => ({ - buildServerApp: jest.fn(), -})) - -// FIXME: TypeError: Cannot read property 'orderID' of undefined -xdescribe("Request for order", () => { - let req - let res - let next - const sendMock = jest.fn() - - describe("/orders/:orderID", () => { - beforeEach(() => { - req = { - path: "/orders/123", - originalUrl: "/orders/123", - query: {}, - header: () => "referrer", - } - res = { - locals: { - sd: { - CURRENT_USER: null, - }, - }, - status: jest.fn(() => ({ send: sendMock })), - redirect: jest.fn(), - } - next = jest.fn() - stitch.mockReset() - buildServerApp.mockReset() - sendMock.mockReset() - }) - - it("redirects an unauthenticated user to log in", done => { - checkoutFlow(req, res, next).then(() => { - expect(res.redirect).toHaveBeenCalledWith( - "/login?redirectTo=%2Forders%2F123" - ) - done() - }) - }) - - it("permits an authenticated user access", done => { - res.locals.sd.CURRENT_USER = { - id: "user1234", - } - buildServerApp.mockResolvedValue({}) - - checkoutFlow(req, res, next).then(() => { - expect(res.redirect).not.toHaveBeenCalled() - expect(buildServerApp).toHaveBeenCalled() - done() - }) - }) - - it("serves a 404 when an order is not found", done => { - res.locals.sd.CURRENT_USER = { - id: "user1234", - } - buildServerApp.mockRejectedValue({ - message: "asdfadsfsda Received status code 404 adsfasd", - }) - - checkoutFlow(req, res, next).then(() => { - expect(buildServerApp).toHaveBeenCalled() - expect(next).toHaveBeenCalledWith( - expect.objectContaining({ - message: "Order Not Found", - status: 404, - }) - ) - done() - }) - }) - }) -}) diff --git a/src/desktop/apps/order/client.js b/src/desktop/apps/order/client.js deleted file mode 100644 index 1b58f48a5dd..00000000000 --- a/src/desktop/apps/order/client.js +++ /dev/null @@ -1,87 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/client" -import { data as sd } from "sharify" -import { routes } from "v2/Apps/Order/routes" -import mediator from "desktop/lib/mediator.coffee" -import React from "react" -import ReactDOM from "react-dom" -import styled from "styled-components" -import User from "desktop/models/user.coffee" -import Artwork from "desktop/models/artwork.coffee" -import ArtworkInquiry from "desktop/models/artwork_inquiry.coffee" -import openInquiryQuestionnaireFor from "desktop/components/inquiry_questionnaire/index.coffee" -import { enableIntercom } from "lib/intercom" - -mediator.on("openOrdersContactArtsyModal", 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(() => { - openInquiryQuestionnaireFor({ - user, - artwork, - inquiry, - ask_specialist: true, - }) - }) - } -}) - -mediator.on("enableIntercomForBuyers", options => { - enableIntercom(options) -}) - -// Track page views for order checkout flow: shipping, payment and review. -// These events are triggered from Reaction. -const orderCheckoutFlowEvents = [ - "order:shipping", - "order:payment", - "order:review", - "order:status", -] -orderCheckoutFlowEvents.map(eventName => { - mediator.on(eventName, () => { - window.analytics.page( - { path: window.location.pathname }, - { integrations: { Marketo: false } } - ) - // Reset timers that track time on page since we're tracking each order - // checkout view as a separate page. - 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) - }) - }) -}) - -buildClientApp({ - routes, - context: { - user: sd.CURRENT_USER, - mediator, - isEigen: sd.EIGEN, - }, - history: { - options: { - useBeforeUnload: true, - }, - }, -}) - .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/order/routes.tsx b/src/desktop/apps/order/routes.tsx deleted file mode 100644 index 3aaf311074b..00000000000 --- a/src/desktop/apps/order/routes.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { buildServerApp } from "v2/Artsy/Router/server" -import { buildServerAppContext } from "desktop/lib/buildServerAppContext" -import { routes } from "v2/Apps/Order/routes" -import { stitch } from "@artsy/stitch" -const metaphysics = require("lib/metaphysics.coffee") - -export const checkoutFlow = async (req, res, next) => { - if (!res.locals.sd.CURRENT_USER) { - return res.redirect( - `/login?redirectTo=${encodeURIComponent(req.originalUrl)}` - ) - } - try { - const { - bodyHTML, - redirect, - status, - headTags, - scripts, - styleTags, - } = await buildServerApp({ - routes, - url: req.url, - userAgent: req.header("User-Agent"), - context: buildServerAppContext(req, res), - }) - - if (redirect) { - res.redirect(302, redirect.url) - return - } - - const headerLogoHref = await getArtworkHref(req) - - // Render layout - const layout = await stitch({ - basePath: __dirname, - layout: - "../../components/main_layout/templates/react_minimal_header.jade", - blocks: { - head: () => headTags, - body: bodyHTML, - }, - locals: { - ...res.locals, - assetPackage: "order", - // header logo should link back to originating artwork - headerLogoHref, - hideHeaderOnEigen: res.locals.sd.EIGEN, - options: { - stripev3: true, - }, - scripts, - styleTags, - }, - }) - - res.status(status).send(layout) - } catch (error) { - next(error) - } -} - -async function getArtworkHref(req) { - try { - const { order } = await metaphysics({ - query: OrderHeaderQuery(req.params.orderID), - req, - }) - return order.lineItems.edges[0].node.artwork.href - } catch (e) { - console.error(e) - return "/" - } -} - -function OrderHeaderQuery(orderId) { - return ` - query OrderHeaderQuery { - order(id: "${orderId}") { - id - lineItems { - edges { - node { - artwork { - href - } - } - } - } - } - }` -} diff --git a/src/desktop/apps/order/server.js b/src/desktop/apps/order/server.js deleted file mode 100644 index 6a833cefe19..00000000000 --- a/src/desktop/apps/order/server.js +++ /dev/null @@ -1,7 +0,0 @@ -import express from "express" -import { checkoutFlow } from "desktop/apps/order/routes" -import { skipIfClientSideRoutingEnabled } from "desktop/components/split_test/skipIfClientSideRoutingEnabled" - -export const app = express() - -app.get("/orders/:orderID*", skipIfClientSideRoutingEnabled, checkoutFlow) diff --git a/src/desktop/apps/purchases/client.tsx b/src/desktop/apps/purchases/client.tsx deleted file mode 100644 index b9056a30ed6..00000000000 --- a/src/desktop/apps/purchases/client.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/client" -import { data as sd } from "sharify" -import { routes } from "v2/Apps/Purchase/routes" -import React from "react" -import ReactDOM from "react-dom" -import { setupArtistSignUpModal } from "desktop/apps/artist/components/cta" - -const mediator = require("desktop/lib/mediator.coffee") - -buildClientApp({ - routes, - context: { - user: sd.CURRENT_USER, - mediator, - } as any, -}) - .then(({ ClientApp }) => { - ReactDOM.hydrate( - , - document.getElementById("react-root"), - () => { - setupArtistSignUpModal() - } - ) - }) - .catch(error => { - console.error(error) - }) - -if (module.hot) { - module.hot.accept() -} diff --git a/src/desktop/apps/purchases/server.tsx b/src/desktop/apps/purchases/server.tsx deleted file mode 100644 index dd697500a50..00000000000 --- a/src/desktop/apps/purchases/server.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { buildServerApp } from "v2/Artsy/Router/server" -import { stitch } from "@artsy/stitch" -import { routes } from "v2/Apps/Purchase/routes" -import React from "react" -import { buildServerAppContext } from "desktop/lib/buildServerAppContext" -import express, { Request, Response, NextFunction } from "express" - -export const app = express() - -app.get( - "/user/purchases", - async (req: Request, res: Response, next: NextFunction) => { - try { - const context = buildServerAppContext(req, res, {}) - const { - bodyHTML, - redirect, - status, - headTags, - styleTags, - scripts, - } = await buildServerApp({ - routes, - url: req.url, - userAgent: req.header("User-Agent"), - context, - }) - - if (redirect) { - res.redirect(302, redirect.url) - return - } - - // Render layout - const layout = await stitch({ - basePath: __dirname, - layout: "../../components/main_layout/templates/react_redesign.jade", - blocks: { - head: () => {headTags}, - body: bodyHTML, - }, - locals: { - ...res.locals, - assetPackage: "purchases", - scripts, - styleTags, - }, - }) - - res.status(status).send(layout) - } catch (error) { - next(error) - } - } -) diff --git a/src/desktop/apps/search2/client.tsx b/src/desktop/apps/search2/client.tsx deleted file mode 100644 index c961bb842fd..00000000000 --- a/src/desktop/apps/search2/client.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/client" -import { routes } from "v2/Apps/Search/routes" -import { data as sd } from "sharify" -import React from "react" -import ReactDOM from "react-dom" - -const mediator = require("desktop/lib/mediator.coffee") - -buildClientApp({ - routes, - context: { - user: sd.CURRENT_USER, - mediator, - }, -}) - .then(({ ClientApp }) => { - ReactDOM.hydrate(, document.getElementById("react-root")) - document.getElementById("loading-container").remove() - }) - .catch(error => { - console.error(error) - }) - -if (module.hot) { - module.hot.accept() -} diff --git a/src/desktop/apps/search2/server.tsx b/src/desktop/apps/search2/server.tsx deleted file mode 100644 index a0864300f06..00000000000 --- a/src/desktop/apps/search2/server.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { stitch } from "@artsy/stitch" -import express, { Request, Response, NextFunction } from "express" -import { stringify } from "querystring" -import { SearchResultsSkeleton } from "v2/Apps/Search/Components/SearchResultsSkeleton" -import React from "react" -import { StitchWrapper } from "desktop/components/react/stitch_components/StitchWrapper" -import { skipIfClientSideRoutingEnabled } from "desktop/components/split_test/skipIfClientSideRoutingEnabled" - -export const app = express() - -app.get( - "/search/:tab?", - skipIfClientSideRoutingEnabled, - async (req: Request, res: Response, next: NextFunction) => { - if (!req.query.term) { - if (req.query.q) { - const query = stringify({ term: req.query.q }) - res.locals.sd.searchQuery = req.query.q - res.redirect(302, `/search?${query}`) - return - } else { - res.redirect(302, "/") - return - } - } else { - res.locals.sd.searchQuery = req.query.term - } - try { - const layout = await stitch({ - basePath: __dirname, - layout: "templates/index.jade", - locals: { - ...res.locals, - assetPackage: "search2", - }, - blocks: { - loadingComponent: _props => { - return ( - - - - ) - }, - }, - }) - - res.send(layout) - } catch (error) { - next(error) - } - } -) diff --git a/src/desktop/apps/search2/templates/index.jade b/src/desktop/apps/search2/templates/index.jade deleted file mode 100644 index bfc1488d17c..00000000000 --- a/src/desktop/apps/search2/templates/index.jade +++ /dev/null @@ -1,9 +0,0 @@ -extends ../../../components/main_layout/templates/redesign - -append locals - - assetPackage = 'search2' - -block body - #react-root - #loading-container - != loadingComponent \ No newline at end of file diff --git a/src/desktop/apps/viewing-room/client.tsx b/src/desktop/apps/viewing-room/client.tsx deleted file mode 100644 index 4d4074ee39f..00000000000 --- a/src/desktop/apps/viewing-room/client.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { buildClientApp } from "v2/Artsy/Router/client" -import { data as sd } from "sharify" -import { routes as viewingRoomRoutes } from "v2/Apps/ViewingRoom/routes" -import React from "react" -import ReactDOM from "react-dom" -import { loadableReady } from "@loadable/component" - -const mediator = require("desktop/lib/mediator.coffee") - -buildClientApp({ - routes: viewingRoomRoutes, - context: { - user: sd.CURRENT_USER, - mediator, - }, -}) - .then(({ ClientApp }) => { - loadableReady(() => { - ReactDOM.hydrate(, document.getElementById("react-root")) - }) - }) - .catch(error => { - console.error(error) - }) - -if (module.hot) { - module.hot.accept() -} diff --git a/src/desktop/apps/viewing-room/server.tsx b/src/desktop/apps/viewing-room/server.tsx deleted file mode 100644 index 5b78c63862c..00000000000 --- a/src/desktop/apps/viewing-room/server.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { buildServerApp } from "v2/Artsy/Router/server" -import { stitch } from "@artsy/stitch" -import { routes as viewingRoomRoutes } from "v2/Apps/ViewingRoom/routes" -import React from "react" -import { buildServerAppContext } from "desktop/lib/buildServerAppContext" -import express, { Request, Response, NextFunction } from "express" -import { skipIfClientSideRoutingEnabled } from "desktop/components/split_test/skipIfClientSideRoutingEnabled" - -export const app = express() - -app.get( - "/viewing-room*", - skipIfClientSideRoutingEnabled, - async (req: Request, res: Response, next: NextFunction) => { - try { - const { - bodyHTML, - redirect, - status, - headTags, - styleTags, - scripts, - } = await buildServerApp({ - context: buildServerAppContext(req, res), - routes: viewingRoomRoutes, - url: req.url, - userAgent: req.header("User-Agent"), - }) - - if (redirect) { - res.redirect(302, redirect.url) - return - } - - // Render layout - const layout = await stitch({ - basePath: __dirname, - layout: "../../components/main_layout/templates/react_redesign.jade", - blocks: { - head: () => {headTags}, - body: bodyHTML, - }, - locals: { - ...res.locals, - assetPackage: "viewing-room", - scripts, - styleTags, - }, - }) - - res.status(status).send(layout) - } catch (error) { - next(error) - } - } -) diff --git a/src/desktop/assets/analytics.coffee b/src/desktop/assets/analytics.coffee index 20beedf7f33..ae3f3fe7422 100644 --- a/src/desktop/assets/analytics.coffee +++ b/src/desktop/assets/analytics.coffee @@ -45,18 +45,16 @@ trackEvent = (data) -> trackingData = _.omit data, 'action_type' trackingOptions = {} - # FIXME: Remove after A/B test ends - if sd.CLIENT_NAVIGATION_V5 == "experiment" - referrer = analytics.__artsyReferrer - # Grab referrer from our trackingMiddleware in Reaction, since we're in a - # single-page-app context and the value will need to be refreshed on route - # change. See: https://github.com/artsy/reaction/blob/master/src/Artsy/Analytics/trackingMiddleware.ts - if referrer - trackingOptions = { - page: { - referrer: referrer - } + referrer = analytics.__artsyReferrer + # Grab referrer from our trackingMiddleware in Reaction, since we're in a + # single-page-app context and the value will need to be refreshed on route + # change. See: https://github.com/artsy/reaction/blob/master/src/Artsy/Analytics/trackingMiddleware.ts + if referrer + trackingOptions = { + page: { + referrer: referrer } + } analytics.track data.action_type, trackingData, trackingOptions else diff --git a/src/desktop/assets/artist.js b/src/desktop/assets/artist.js deleted file mode 100644 index 35f587ae198..00000000000 --- a/src/desktop/assets/artist.js +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/artist/client" diff --git a/src/desktop/assets/artist.styl b/src/desktop/assets/artist.styl deleted file mode 100644 index 38366117f4d..00000000000 --- a/src/desktop/assets/artist.styl +++ /dev/null @@ -1,2 +0,0 @@ -.artist__foo - width: 100% diff --git a/src/desktop/assets/experimental-app-shell.styl b/src/desktop/assets/artsy-v2.styl similarity index 100% rename from src/desktop/assets/experimental-app-shell.styl rename to src/desktop/assets/artsy-v2.styl diff --git a/src/desktop/assets/artsy-v2.tsx b/src/desktop/assets/artsy-v2.tsx new file mode 100644 index 00000000000..c6f9451600a --- /dev/null +++ b/src/desktop/assets/artsy-v2.tsx @@ -0,0 +1 @@ +import "desktop/apps/artsy-v2/client" diff --git a/src/desktop/assets/artwork.js b/src/desktop/assets/artwork.js deleted file mode 100644 index 89b8f301a76..00000000000 --- a/src/desktop/assets/artwork.js +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/artwork/client" diff --git a/src/desktop/assets/collect.styl b/src/desktop/assets/collect.styl deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/desktop/assets/collect.ts b/src/desktop/assets/collect.ts deleted file mode 100644 index e6ddc3c2206..00000000000 --- a/src/desktop/assets/collect.ts +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/collect/client" diff --git a/src/desktop/assets/conversations.styl b/src/desktop/assets/conversations.styl deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/desktop/assets/conversations.tsx b/src/desktop/assets/conversations.tsx deleted file mode 100644 index 5cd782417f5..00000000000 --- a/src/desktop/assets/conversations.tsx +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/conversations/client" diff --git a/src/desktop/assets/experimental-app-shell.tsx b/src/desktop/assets/experimental-app-shell.tsx deleted file mode 100644 index 5d4abb16711..00000000000 --- a/src/desktop/assets/experimental-app-shell.tsx +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/experimental-app-shell/client" diff --git a/src/desktop/assets/identity_verification.styl b/src/desktop/assets/identity_verification.styl deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/desktop/assets/identity_verification.ts b/src/desktop/assets/identity_verification.ts deleted file mode 100644 index d29090814f0..00000000000 --- a/src/desktop/assets/identity_verification.ts +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/identity_verification/client" diff --git a/src/desktop/assets/order.js b/src/desktop/assets/order.js deleted file mode 100644 index d1039da9780..00000000000 --- a/src/desktop/assets/order.js +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/order/client" diff --git a/src/desktop/assets/purchases.js b/src/desktop/assets/purchases.js deleted file mode 100644 index 0c90b83d77d..00000000000 --- a/src/desktop/assets/purchases.js +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/purchases/client" diff --git a/src/desktop/assets/search2.js b/src/desktop/assets/search2.js deleted file mode 100644 index ba540b106b3..00000000000 --- a/src/desktop/assets/search2.js +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/search2/client" diff --git a/src/desktop/assets/search2.styl b/src/desktop/assets/search2.styl deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/desktop/assets/viewing-room.tsx b/src/desktop/assets/viewing-room.tsx deleted file mode 100644 index 29574b5a269..00000000000 --- a/src/desktop/assets/viewing-room.tsx +++ /dev/null @@ -1 +0,0 @@ -import "desktop/apps/viewing-room/client" diff --git a/src/desktop/apps/artist/components/__tests__/cta.jest.ts b/src/desktop/components/artistSignupModal/__tests__/artistSignupModal.tsx similarity index 97% rename from src/desktop/apps/artist/components/__tests__/cta.jest.ts rename to src/desktop/components/artistSignupModal/__tests__/artistSignupModal.tsx index 08498514dac..82a57e7aefb 100644 --- a/src/desktop/apps/artist/components/__tests__/cta.jest.ts +++ b/src/desktop/components/artistSignupModal/__tests__/artistSignupModal.tsx @@ -1,4 +1,4 @@ -import { setupArtistSignUpModal, setCookie, query } from "../cta" +import { setupArtistSignUpModal, setCookie, query } from "../artistSignupModal" import * as helpers from "desktop/lib/openAuthModal" jest.mock("desktop/components/cookies/index.coffee", () => ({ diff --git a/src/desktop/apps/artist/components/cta.ts b/src/desktop/components/artistSignupModal/artistSignupModal.tsx similarity index 99% rename from src/desktop/apps/artist/components/cta.ts rename to src/desktop/components/artistSignupModal/artistSignupModal.tsx index 0564b434c4c..dcdf10559f0 100644 --- a/src/desktop/apps/artist/components/cta.ts +++ b/src/desktop/components/artistSignupModal/artistSignupModal.tsx @@ -2,6 +2,7 @@ import { get } from "lodash" import { data as sd } from "sharify" import { handleScrollingAuthModal } from "desktop/lib/openAuthModal" import { Intent, ContextModule } from "@artsy/cohesion" + const Cookies = require("desktop/components/cookies/index.coffee") const mediator = require("desktop/lib/mediator.coffee") const metaphysics2 = require("lib/metaphysics2.coffee") diff --git a/src/desktop/apps/artwork/components/buyers_premium/index.coffee b/src/desktop/components/artworkBuyersPremium/index.coffee similarity index 64% rename from src/desktop/apps/artwork/components/buyers_premium/index.coffee rename to src/desktop/components/artworkBuyersPremium/index.coffee index b85187b2c9b..6f8731e854a 100644 --- a/src/desktop/apps/artwork/components/buyers_premium/index.coffee +++ b/src/desktop/components/artworkBuyersPremium/index.coffee @@ -1,6 +1,6 @@ -modalize = require '../../../../components/modalize/index.coffee' -Auction = require '../../../../models/auction.coffee' -fetchBuyersPremium = require '../../../../components/buyers_premium/index.coffee' +modalize = require '../modalize/index.coffee' +Auction = require '../../models/auction.coffee' +fetchBuyersPremium = require '../buyers_premium/index.coffee' module.exports = (auction_id) -> $el = $('
') @@ -19,4 +19,4 @@ module.exports = (auction_id) -> $el.html html open() - modal \ No newline at end of file + modal diff --git a/src/desktop/apps/artwork/components/buyers_premium/index.styl b/src/desktop/components/artworkBuyersPremium/index.styl similarity index 85% rename from src/desktop/apps/artwork/components/buyers_premium/index.styl rename to src/desktop/components/artworkBuyersPremium/index.styl index 74f56ee0d8b..6eeef36c983 100644 --- a/src/desktop/apps/artwork/components/buyers_premium/index.styl +++ b/src/desktop/components/artworkBuyersPremium/index.styl @@ -7,4 +7,4 @@ padding (gutter * 3) h1 - sans('l-headline') \ No newline at end of file + sans('l-headline') diff --git a/src/desktop/components/main_layout/templates/experimental_app_shell.jade b/src/desktop/components/main_layout/templates/artsy_v2.jade similarity index 90% rename from src/desktop/components/main_layout/templates/experimental_app_shell.jade rename to src/desktop/components/main_layout/templates/artsy_v2.jade index 571d7941e28..aedb989e293 100644 --- a/src/desktop/components/main_layout/templates/experimental_app_shell.jade +++ b/src/desktop/components/main_layout/templates/artsy_v2.jade @@ -26,6 +26,6 @@ block body include ./json_ld block append scripts - script( src=asset("/assets/experimental-app-shell.js") ) + script( src=asset("/assets/artsy-v2.js") ) != scripts diff --git a/src/desktop/components/split_test/running_tests.coffee b/src/desktop/components/split_test/running_tests.coffee index d73a473cc81..2e789a7b747 100644 --- a/src/desktop/components/split_test/running_tests.coffee +++ b/src/desktop/components/split_test/running_tests.coffee @@ -26,10 +26,4 @@ # this should export empty Object # module.exports = {} -module.exports = { - client_navigation_v5: - key: "client_navigation_v5" - outcomes: - control: 50 - experiment: 50 -} +module.exports = {} diff --git a/src/desktop/components/split_test/skipIfClientSideRoutingEnabled.ts b/src/desktop/components/split_test/skipIfClientSideRoutingEnabled.ts deleted file mode 100644 index 2aa953cf29c..00000000000 --- a/src/desktop/components/split_test/skipIfClientSideRoutingEnabled.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const skipIfClientSideRoutingEnabled = (_req, res, next) => { - // Remove once A/B test completes - if (res.locals.sd.CLIENT_NAVIGATION_V5 === "experiment") { - return next("route") - } - return next() -} diff --git a/src/desktop/config.coffee b/src/desktop/config.coffee index 7d570e28dd2..67e7235b68f 100644 --- a/src/desktop/config.coffee +++ b/src/desktop/config.coffee @@ -46,9 +46,6 @@ module.exports = EF_VENICE: '58f5eb75faef6a3a8e7fe1ad' EF_GUCCI: '5a009372c88a280f5e9efa7e' EF_VIDEO_GUIDE: '5901d64b4682400017f0e3cb' - - # FIXME: Remove experimental flag - EXPERIMENTAL_APP_SHELL: false, FACEBOOK_APP_NAMESPACE: "artsyinc" FACEBOOK_DOMAIN_VERIFICATION: 'yeg3dqrlq548zc77ggvfipouil1l1e' FACEBOOK_ID: null diff --git a/src/desktop/index.js b/src/desktop/index.ts similarity index 74% rename from src/desktop/index.js rename to src/desktop/index.ts index e0950a463bd..09d3302be3a 100644 --- a/src/desktop/index.js +++ b/src/desktop/index.ts @@ -3,19 +3,36 @@ import * as globalReactModules from "desktop/components/react/stitch_components" const app = (module.exports = require("express")()) -// Configure stitch SSR functionality. Mounted here (rather than in setup) so -// changes to stitched code can be hot reloaded. -// See: https://github.com/artsy/stitch/tree/master/src/internal for more info. +/** + * ----------------------------------------------------------------------------- + * + * Developers! Wait! + * + * Before adding a new app to this file, can it live in `v2/Apps/getAppRoutes? + * In most cases, apps built after Jan 2020 can take advantage of our Relay-based + * SSR router (./apps/artsy-v2) which requires no additional server-side setup. + * + * ---------------------------------------------------------------------------- + */ + +/** + * Configure stitch SSR functionality. Mounted here (rather than in setup) so + * changes to stitched code can be hot reloaded. + * + * @see https://github.com/artsy/stitch/tree/master/src/internal for more info. + */ app.use( stitchMiddleware({ + // @ts-ignore modules: globalReactModules, wrapper: globalReactModules.StitchWrapper, }) ) -// NOTE: -// App order matters as some apps establish logic that is shared inside of subapps. -// Apps with hardcoded routes or "RESTful" routes +/** + * NOTE: App order matters as some apps establish logic that is shared inside + * of subapps. Apps with hardcoded routes or "RESTful" routes. + */ app.use(require("./apps/home")) app.use(require("./apps/editorial_features")) @@ -25,20 +42,12 @@ app.use(require("./apps/auctions")) app.use(require("./apps/auctions2").app) app.use(require("./apps/auction_lots")) -// TODO: Remove after AB test ends. -app.use(require("./apps/artist/server").app) -app.use(require("./apps/purchases/server").app) -app.use(require("./apps/conversations/server").app) -app.use(require("./apps/artwork/server").app) -app.use(require("./apps/collect/server").app) -app.use(require("./apps/search2/server").app) +// FIXME: Remove once JSONPage + new app shell is worked out app.use(require("./apps/art_keeps_going/server").app) -app.use(require("./apps/viewing-room/server").app) app.use(require("./apps/artists")) app.use(require("./apps/auction").app) app.use(require("./apps/auction_support")) -app.use(require("./apps/identity_verification/server").app) app.use(require("./apps/about")) app.use(require("./apps/categories").app) app.use(require("./apps/consign").app) @@ -52,7 +61,6 @@ app.use(require("./apps/gene")) app.use(require("./apps/geo")) app.use(require("./apps/jobs")) app.use(require("./apps/notifications")) -app.use(require("./apps/order/server").app) app.use(require("./apps/personalize")) app.use(require("./apps/press")) @@ -101,4 +109,6 @@ app.use(require("./apps/user")) // Used to test various SSR configurations app.use(require("./apps/ssr-experiments/server").app) -app.use(require("./apps/experimental-app-shell/server").app) +// Mount all `v2/Apps`. This ~must~ come last as it mounts our v2 apps in a +// wild-card fashion. +app.use(require("./apps/artsy-v2/server").app) diff --git a/src/desktop/lib/global_client_setup.tsx b/src/desktop/lib/global_client_setup.tsx index 699bf36d248..64fabb4fc6b 100644 --- a/src/desktop/lib/global_client_setup.tsx +++ b/src/desktop/lib/global_client_setup.tsx @@ -126,7 +126,7 @@ function setupJquery() { // once you click it. For these cases do `$el.click -> $(@).hidehover()` and // the menu will hide and then remove the `display` property so the default // CSS will kick in again. - $.fn.hidehover = function () { + $.fn.hidehover = function() { const $el = $(this) $el.css({ display: "none" }) return setTimeout(() => $el.css({ display: "" }), 200) @@ -146,17 +146,10 @@ function setupErrorReporting() { if (sd.NODE_ENV === "production") { Sentry.init({ dsn: sd.SENTRY_PUBLIC_DSN }) - // FIXME: Remove once A/B test ends - Sentry.addBreadcrumb({ - category: "experimental-app-shell-ab-test", - message: `A/B v5 test group: ${sd.CLIENT_NAVIGATION_V5}`, - level: Sentry.Severity.Info, - }) - const user = sd && sd.CURRENT_USER if (sd.CURRENT_USER) { - Sentry.configureScope((scope) => { + Sentry.configureScope(scope => { scope.setUser(_.pick(user, "id", "email")) }) } @@ -182,7 +175,7 @@ export function trackAuthenticationEvents() { const modes = ["login", "signup"] const user = sd && sd.CURRENT_USER - modes.forEach((mode) => { + modes.forEach(mode => { if (Cookies.get(`analytics-${mode}`)) { const data = JSON.parse(Cookies.get(`analytics-${mode}`)) Cookies.expire(`analytics-${mode}`) diff --git a/src/lib/setup_sharify.js b/src/lib/setup_sharify.js index 7c568658776..edaab8cd84d 100644 --- a/src/lib/setup_sharify.js +++ b/src/lib/setup_sharify.js @@ -52,9 +52,6 @@ sharify.data = _.extend( "EF_GUCCI", "EF_VENICE", "EF_VIDEO_GUIDE", - - // FIXME: Remove experimental flag - "EXPERIMENTAL_APP_SHELL", "FACEBOOK_APP_NAMESPACE", "FACEBOOK_ID", "FORCE_CLOUDFRONT_URL", diff --git a/src/typings/sharify.d.ts b/src/typings/sharify.d.ts index 8a44d62ac9e..4202026f00e 100644 --- a/src/typings/sharify.d.ts +++ b/src/typings/sharify.d.ts @@ -20,7 +20,6 @@ declare module "sharify" { readonly APP_URL: string readonly ARTIST_COLLECTIONS_RAIL?: string // TODO: remove after CollectionsRail a/b test readonly ARTIST_COLLECTIONS_RAIL_IDS: string[] - readonly CLIENT_NAVIGATION_V5: "experiment" | "control" // TODO: Remove after A/B test. readonly CMS_URL: string readonly CDN_URL: string CURRENT_PATH: string diff --git a/src/v2/Apps/Artwork/ArtworkApp.tsx b/src/v2/Apps/Artwork/ArtworkApp.tsx index 34c300d2c15..ece96b3fcfc 100644 --- a/src/v2/Apps/Artwork/ArtworkApp.tsx +++ b/src/v2/Apps/Artwork/ArtworkApp.tsx @@ -90,11 +90,6 @@ export class ArtworkApp extends React.Component { // See trackingMiddleware.ts window.analytics.__artsyReferrer = referrer window.analytics.page(properties, { integrations: { Marketo: false } }) - - // TODO: Remove after EXPERIMENTAL_APP_SHELL AB test ends. - // if (sd.CLIENT_NAVIGATION_V5) { - // trackExperimentViewed("client_navigation_v5", properties) - // } } } diff --git a/src/v2/Apps/Artwork/Components/ArtworkSidebar/ArtworkSidebarCommercial.tsx b/src/v2/Apps/Artwork/Components/ArtworkSidebar/ArtworkSidebarCommercial.tsx index 2cf5f7273b1..6a82029af3b 100644 --- a/src/v2/Apps/Artwork/Components/ArtworkSidebar/ArtworkSidebarCommercial.tsx +++ b/src/v2/Apps/Artwork/Components/ArtworkSidebar/ArtworkSidebarCommercial.tsx @@ -41,7 +41,6 @@ export interface ArtworkSidebarCommercialContainerProps mediator: Mediator router?: Router user: User - EXPERIMENTAL_APP_SHELL?: boolean } export interface ArtworkSidebarCommercialContainerState { @@ -51,7 +50,7 @@ export interface ArtworkSidebarCommercialContainerState { selectedEditionSet: EditionSet } -const Row: React.SFC = ({ children, ...others }) => ( +const Row: React.FC = ({ children, ...others }) => ( {children} @@ -63,8 +62,8 @@ const logger = createLogger( @track() export class ArtworkSidebarCommercialContainer extends React.Component< -ArtworkSidebarCommercialContainerProps, -ArtworkSidebarCommercialContainerState + ArtworkSidebarCommercialContainerProps, + ArtworkSidebarCommercialContainerState > { state: ArtworkSidebarCommercialContainerState = { isCommittingCreateOrderMutation: false, @@ -235,13 +234,7 @@ ArtworkSidebarCommercialContainerState ) } else { const url = `/orders/${orderOrError.order.internalID}` - - // FIXME: Remove once A/B test completes - if (this.props.EXPERIMENTAL_APP_SHELL) { - this.props.router.push(url) - } else { - window.location.assign(url) - } + this.props.router.push(url) } } ) @@ -326,13 +319,7 @@ ArtworkSidebarCommercialContainerState ) } else { const url = `/orders/${orderOrError.order.internalID}/offer` - - // FIXME: Remove once A/B test completes - if (this.props.EXPERIMENTAL_APP_SHELL) { - this.props.router.push(url) - } else { - window.location.assign(url) - } + this.props.router.push(url) } } ) @@ -378,16 +365,16 @@ ArtworkSidebarCommercialContainerState ) ) : ( - <> - {this.renderEditionSets(artworkEcommerceAvailable)} - {selectedEditionSet && ( - <> - - {this.renderSaleMessage(selectedEditionSet.sale_message)} - - )} - - )} + <> + {this.renderEditionSets(artworkEcommerceAvailable)} + {selectedEditionSet && ( + <> + + {this.renderSaleMessage(selectedEditionSet.sale_message)} + + )} + + )} {artworkEcommerceAvailable && (artwork.shippingOrigin || artwork.shippingInfo) && } @@ -408,12 +395,12 @@ ArtworkSidebarCommercialContainerState )} {artwork.is_inquireable || - artwork.is_acquireable || - artwork.is_offerable ? ( - artwork.sale_message && - ) : ( - - )} + artwork.is_acquireable || + artwork.is_offerable ? ( + artwork.sale_message && + ) : ( + + )} {artwork.is_acquireable && ( @@ -54,8 +54,8 @@ const logger = createLogger("Order/Routes/NewPayment/index.tsx") @track() export class NewPaymentRoute extends Component< -NewPaymentProps, -NewPaymentState + NewPaymentProps, + NewPaymentState > { paymentPicker = React.createRef() state = { @@ -295,7 +295,7 @@ NewPaymentState artistId() { return get( this.props.order, - o => o.lineItems.edges[0].node.artwork.artists[0].slug + (o) => o.lineItems.edges[0].node.artwork.artists[0].slug ) } @@ -347,6 +347,3 @@ export const NewPaymentFragmentContainer = createFragmentContainer( `, } ) - -// For bundle splitting in router -export default NewPaymentFragmentContainer diff --git a/src/v2/Apps/Order/Routes/Offer/index.tsx b/src/v2/Apps/Order/Routes/Offer/index.tsx index c69d220207a..4e7fe03ed40 100644 --- a/src/v2/Apps/Order/Routes/Offer/index.tsx +++ b/src/v2/Apps/Order/Routes/Offer/index.tsx @@ -60,7 +60,7 @@ export class OfferRoute extends Component { highSpeedBumpEncountered: false, } - @track(props => ({ + @track((props) => ({ order_id: props.order.internalID, action_type: Schema.ActionType.FocusedOnOfferInput, flow: Schema.Flow.MakeOffer, @@ -69,7 +69,7 @@ export class OfferRoute extends Component { // noop } - @track(props => ({ + @track((props) => ({ order_id: props.order.internalID, action_type: Schema.ActionType.ViewedOfferTooLow, flow: Schema.Flow.MakeOffer, @@ -84,7 +84,7 @@ export class OfferRoute extends Component { }) } - @track(props => ({ + @track((props) => ({ order_id: props.order.internalID, action_type: Schema.ActionType.ViewedOfferHigherThanListPrice, flow: Schema.Flow.MakeOffer, @@ -235,7 +235,7 @@ export class OfferRoute extends Component { showError={ this.state.formIsDirty && this.state.offerValue <= 0 } - onChange={offerValue => this.setState({ offerValue })} + onChange={(offerValue) => this.setState({ offerValue })} onFocus={this.onOfferInputFocus.bind(this)} /> @@ -247,7 +247,7 @@ export class OfferRoute extends Component { + onChange={(offerNoteValue) => this.setState({ offerNoteValue }) } artworkId={artworkId} @@ -337,6 +337,3 @@ export const OfferFragmentContainer = createFragmentContainer( `, } ) - -// For bundle splitting in router -export default OfferFragmentContainer diff --git a/src/v2/Apps/Order/Routes/Payment/index.tsx b/src/v2/Apps/Order/Routes/Payment/index.tsx index 0d20c2d5bfd..7267ea9a462 100644 --- a/src/v2/Apps/Order/Routes/Payment/index.tsx +++ b/src/v2/Apps/Order/Routes/Payment/index.tsx @@ -30,7 +30,7 @@ import { } from "v2/Apps/Order/Utils/commitMutation" import { AnalyticsSchema, track } from "v2/Artsy" -export const ContinueButton = props => ( +export const ContinueButton = (props) => ( @@ -241,6 +241,3 @@ export const PaymentFragmentContainer = createFragmentContainer( `, } ) - -// For bundle splitting in router -export default PaymentFragmentContainer diff --git a/src/v2/Apps/Order/Routes/Reject/index.tsx b/src/v2/Apps/Order/Routes/Reject/index.tsx index cf506e14b52..4529dfdf09e 100644 --- a/src/v2/Apps/Order/Routes/Reject/index.tsx +++ b/src/v2/Apps/Order/Routes/Reject/index.tsx @@ -211,6 +211,3 @@ export const RejectFragmentContainer = createFragmentContainer( `, } ) - -// For bundle splitting in router -export default RejectFragmentContainer diff --git a/src/v2/Apps/Order/Routes/Respond/index.tsx b/src/v2/Apps/Order/Routes/Respond/index.tsx index d9a08ba3b25..98f01e91a72 100644 --- a/src/v2/Apps/Order/Routes/Respond/index.tsx +++ b/src/v2/Apps/Order/Routes/Respond/index.tsx @@ -71,7 +71,7 @@ export class RespondRoute extends Component { highSpeedBumpEncountered: false, } - @track(props => ({ + @track((props) => ({ order_id: props.order.internalID, action_type: Schema.ActionType.FocusedOnOfferInput, flow: Schema.Flow.MakeOffer, @@ -80,7 +80,7 @@ export class RespondRoute extends Component { // noop } - @track(props => ({ + @track((props) => ({ order_id: props.order.internalID, action_type: Schema.ActionType.ViewedOfferTooLow, flow: Schema.Flow.MakeOffer, @@ -95,7 +95,7 @@ export class RespondRoute extends Component { }) } - @track(props => ({ + @track((props) => ({ order_id: props.order.internalID, action_type: Schema.ActionType.ViewedOfferHigherThanListPrice, flow: Schema.Flow.MakeOffer, @@ -272,7 +272,7 @@ export class RespondRoute extends Component { showError={ this.state.formIsDirty && this.state.offerValue <= 0 } - onChange={offerValue => this.setState({ offerValue })} + onChange={(offerValue) => this.setState({ offerValue })} onFocus={this.onOfferInputFocus.bind(this)} /> @@ -282,7 +282,7 @@ export class RespondRoute extends Component { > + onChange={(offerNoteValue) => this.setState({ offerNoteValue }) } artworkId={artworkId} @@ -393,6 +393,3 @@ export const RespondFragmentContainer = createFragmentContainer( `, } ) - -// For bundle splitting in router -export default RespondFragmentContainer diff --git a/src/v2/Apps/Order/Routes/Review/index.tsx b/src/v2/Apps/Order/Routes/Review/index.tsx index 5ccc674de64..4e4ca2bd8ba 100644 --- a/src/v2/Apps/Order/Routes/Review/index.tsx +++ b/src/v2/Apps/Order/Routes/Review/index.tsx @@ -65,7 +65,7 @@ export class ReviewRoute extends Component { } } - @track(props => ({ + @track((props) => ({ action_type: props.order.mode === "BUY" ? Schema.ActionType.SubmittedOrder @@ -85,7 +85,7 @@ export class ReviewRoute extends Component { this.props.order.mode === "BUY" ? (await this.submitBuyOrder()).commerceSubmitOrder.orderOrError : (await this.submitOffer(setupIntentId)).commerceSubmitOrderWithOffer - .orderOrError + .orderOrError if (orderOrError.error) { this.handleSubmitError(orderOrError.error) @@ -97,7 +97,7 @@ export class ReviewRoute extends Component { ) { this.state.stripe .handleCardAction(orderOrError.actionData.clientSecret) - .then(result => { + .then((result) => { if (result.error) { this.props.dialog.showErrorDialog({ title: "An error occurred", @@ -115,7 +115,7 @@ export class ReviewRoute extends Component { ) { this.state.stripe .handleCardSetup(orderOrError.actionData.clientSecret) - .then(result => { + .then((result) => { if (result.error) { this.props.dialog.showErrorDialog({ title: "An error occurred", @@ -289,14 +289,14 @@ export class ReviewRoute extends Component { artistId() { return get( this.props.order, - o => o.lineItems.edges[0].node.artwork.artists[0].slug + (o) => o.lineItems.edges[0].node.artwork.artists[0].slug ) } routeToArtworkPage() { const artworkId = get( this.props.order, - o => o.lineItems.edges[0].node.artwork.slug + (o) => o.lineItems.edges[0].node.artwork.slug ) // Don't confirm whether or not you want to leave the page this.props.route.onTransition = () => null @@ -448,6 +448,3 @@ export const ReviewFragmentContainer = createFragmentContainer( `, } ) - -// For bundle splitting in router -export default ReviewFragmentContainer diff --git a/src/v2/Apps/Order/Routes/Shipping/index.tsx b/src/v2/Apps/Order/Routes/Shipping/index.tsx index d4f390590df..bdaeb778bd9 100644 --- a/src/v2/Apps/Order/Routes/Shipping/index.tsx +++ b/src/v2/Apps/Order/Routes/Shipping/index.tsx @@ -79,7 +79,7 @@ const logger = createLogger("Order/Routes/Shipping/index.tsx") export class ShippingRoute extends Component { state: ShippingState = { shippingOption: (this.props.order.requestedFulfillment && - this.props.order.requestedFulfillment.__typename !== "CommerceShip" + this.props.order.requestedFulfillment.__typename !== "CommerceShip" ? "PICKUP" : "SHIP") as CommerceOrderFulfillmentTypeEnum, address: this.startingAddress, @@ -87,8 +87,8 @@ export class ShippingRoute extends Component { addressTouched: {}, phoneNumber: this.props.order.requestedFulfillment && - (this.props.order.requestedFulfillment.__typename === "CommerceShip" || - this.props.order.requestedFulfillment.__typename === "CommercePickup") + (this.props.order.requestedFulfillment.__typename === "CommerceShip" || + this.props.order.requestedFulfillment.__typename === "CommercePickup") ? this.props.order.requestedFulfillment.phoneNumber : "", phoneNumberError: "", @@ -231,7 +231,7 @@ export class ShippingRoute extends Component { handleSubmitError(error: { code: string; data: string }) { logger.error(error) - const parsedData = get(error, e => JSON.parse(e.data), {}) + const parsedData = get(error, (e) => JSON.parse(e.data), {}) if ( error.code === "missing_region" || error.code === "missing_country" || @@ -267,7 +267,8 @@ export class ShippingRoute extends Component { country: validatePresence(country), postalCode: usOrCanada && validatePresence(postalCode), } - const hasErrors = Object.keys(errors).filter(key => errors[key]).length > 0 + const hasErrors = + Object.keys(errors).filter((key) => errors[key]).length > 0 return { errors, @@ -300,7 +301,7 @@ export class ShippingRoute extends Component { }) } - onPhoneNumberChange: PhoneNumberChangeHandler = phoneNumber => { + onPhoneNumberChange: PhoneNumberChangeHandler = (phoneNumber) => { const { error } = this.validatePhoneNumber(phoneNumber) this.setState({ phoneNumber, @@ -334,7 +335,7 @@ export class ShippingRoute extends Component { } = this.state const artwork = get( this.props, - props => props.order.lineItems.edges[0].node.artwork + (props) => props.order.lineItems.edges[0].node.artwork ) return ( @@ -508,6 +509,3 @@ export const ShippingFragmentContainer = createFragmentContainer( `, } ) - -// For bundle splitting in router -export default ShippingFragmentContainer diff --git a/src/v2/Apps/Order/Routes/Status/index.tsx b/src/v2/Apps/Order/Routes/Status/index.tsx index fa4609b2e73..460f5c223db 100644 --- a/src/v2/Apps/Order/Routes/Status/index.tsx +++ b/src/v2/Apps/Order/Routes/Status/index.tsx @@ -53,26 +53,26 @@ export class StatusRoute extends Component { case "SUBMITTED": return isOfferFlow ? { - title: "Your offer has been submitted", - description: ( - <> - The seller will respond to your offer by {stateExpiresAt}. + title: "Your offer has been submitted", + description: ( + <> + The seller will respond to your offer by {stateExpiresAt}. Keep in mind making an offer doesn’t guarantee you the work. - - ), - } + + ), + } : { - title: "Your order has been submitted", - description: ( - <> - Thank you for your purchase. You will receive a confirmation + title: "Your order has been submitted", + description: ( + <> + Thank you for your purchase. You will receive a confirmation email by {stateExpiresAt}. -
+
Disruptions caused by COVID-19 may cause delays — we appreciate your understanding. - - ), - } + + ), + } case "APPROVED": return { title: isOfferFlow ? "Offer accepted" : "Your order is confirmed", @@ -85,25 +85,25 @@ export class StatusRoute extends Component { your understanding. ) : ( - <> - Thank you for your purchase. A specialist will contact you within - 2 business days to coordinate pickup. -
+ <> + Thank you for your purchase. A specialist will contact you within + 2 business days to coordinate pickup. +
Disruptions caused by COVID-19 may cause delays — we appreciate your understanding. - - ), + + ), } case "FULFILLED": { return isShip ? { - title: "Your order has shipped", - description: this.getFulfilmentDescription(), - } + title: "Your order has shipped", + description: this.getFulfilmentDescription(), + } : { - title: "Your order has been picked up", - description: null, - } + title: "Your order has been picked up", + description: null, + } } case "CANCELED": case "REFUNDED": @@ -205,7 +205,7 @@ export class StatusRoute extends Component { getFulfilmentDescription(): React.ReactNode { const fulfillment = get( this.props.order, - o => o.lineItems.edges[0].node.fulfillments.edges[0].node + (o) => o.lineItems.edges[0].node.fulfillments.edges[0].node ) if (!fulfillment) { @@ -272,16 +272,16 @@ export class StatusRoute extends Component { /> ) : ( - - )} + + )} } @@ -373,6 +373,3 @@ export const StatusFragmentContainer = createFragmentContainer(StatusRoute, { } `, }) - -// For bundle splitting in router -export default StatusFragmentContainer diff --git a/src/v2/Apps/Order/routes.tsx b/src/v2/Apps/Order/routes.tsx index 4d4130f1d30..75abec965f6 100644 --- a/src/v2/Apps/Order/routes.tsx +++ b/src/v2/Apps/Order/routes.tsx @@ -6,17 +6,18 @@ import { Redirect, RedirectException, RouteConfig } from "found" import * as React from "react" import { graphql } from "react-relay" +import { RespondFragmentContainer as RespondRoute } from "./Routes/Respond" +import { OfferFragmentContainer as OfferRoute } from "./Routes/Offer" +import { ShippingFragmentContainer as ShippingRoute } from "./Routes/Shipping" +import { PaymentFragmentContainer as PaymentRoute } from "./Routes/Payment" +import { NewPaymentFragmentContainer as NewPaymentRoute } from "./Routes/NewPayment" +import { CounterFragmentContainer as CounterRoute } from "./Routes/Counter" +import { ReviewFragmentContainer as ReviewRoute } from "./Routes/Review" +import { AcceptFragmentContainer as AcceptRoute } from "./Routes/Accept" +import { RejectFragmentContainer as DeclineRoute } from "./Routes/Reject" +import { StatusFragmentContainer as StatusRoute } from "./Routes/Status" + const OrderApp = loadable(() => import("./OrderApp")) -const RespondRoute = loadable(() => import("./Routes/Respond")) -const OfferRoute = loadable(() => import("./Routes/Offer")) -const ShippingRoute = loadable(() => import("./Routes/Shipping")) -const PaymentRoute = loadable(() => import("./Routes/Payment")) -const NewPaymentRoute = loadable(() => import("./Routes/NewPayment")) -const CounterRoute = loadable(() => import("./Routes/Counter")) -const ReviewRoute = loadable(() => import("./Routes/Review")) -const AcceptRoute = loadable(() => import("./Routes/Accept")) -const DeclineRoute = loadable(() => import("./Routes/Reject")) -const StatusRoute = loadable(() => import("./Routes/Status")) // FIXME: // * `render` functions requires casting @@ -74,10 +75,7 @@ export const routes: RouteConfig[] = [ children: [ { path: "respond", - getComponent: () => RespondRoute, - prepare: () => { - RespondRoute.preload() - }, + Component: RespondRoute, shouldWarnBeforeLeaving: true, query: graphql` query routes_RespondQuery($orderID: ID!) { @@ -92,10 +90,7 @@ export const routes: RouteConfig[] = [ }, { path: "offer", - getComponent: () => OfferRoute, - prepare: () => { - OfferRoute.preload() - }, + Component: OfferRoute, shouldWarnBeforeLeaving: true, query: graphql` query routes_OfferQuery($orderID: ID!) { @@ -110,10 +105,7 @@ export const routes: RouteConfig[] = [ }, { path: "shipping", - getComponent: () => ShippingRoute, - prepare: () => { - ShippingRoute.preload() - }, + Component: ShippingRoute, shouldWarnBeforeLeaving: true, query: graphql` query routes_ShippingQuery($orderID: ID!) { @@ -128,10 +120,7 @@ export const routes: RouteConfig[] = [ }, { path: "payment", - getComponent: () => PaymentRoute, - prepare: () => { - PaymentRoute.preload() - }, + Component: PaymentRoute, shouldWarnBeforeLeaving: true, query: graphql` query routes_PaymentQuery($orderID: ID!) { @@ -149,10 +138,7 @@ export const routes: RouteConfig[] = [ }, { path: "payment/new", - getComponent: () => NewPaymentRoute, - prepare: () => { - NewPaymentRoute.preload() - }, + Component: NewPaymentRoute, shouldWarnBeforeLeaving: true, query: graphql` query routes_NewPaymentQuery($orderID: ID!) { @@ -170,10 +156,7 @@ export const routes: RouteConfig[] = [ }, { path: "review/counter", - getComponent: () => CounterRoute, - prepare: () => { - CounterRoute.preload() - }, + Component: CounterRoute, shouldWarnBeforeLeaving: true, query: graphql` query routes_CounterQuery($orderID: ID!) { @@ -188,10 +171,7 @@ export const routes: RouteConfig[] = [ }, { path: "review", - getComponent: () => ReviewRoute, - prepare: () => { - ReviewRoute.preload() - }, + Component: ReviewRoute, shouldWarnBeforeLeaving: true, query: graphql` query routes_ReviewQuery($orderID: ID!) { @@ -206,10 +186,7 @@ export const routes: RouteConfig[] = [ }, { path: "review/accept", - getComponent: () => AcceptRoute, - prepare: () => { - AcceptRoute.preload() - }, + Component: AcceptRoute, query: graphql` query routes_AcceptQuery($orderID: ID!) { order: commerceOrder(id: $orderID) { @@ -223,10 +200,7 @@ export const routes: RouteConfig[] = [ }, { path: "review/decline", - getComponent: () => DeclineRoute, - prepare: () => { - DeclineRoute.preload() - }, + Component: DeclineRoute, query: graphql` query routes_RejectQuery($orderID: ID!) { order: commerceOrder(id: $orderID) { @@ -237,10 +211,7 @@ export const routes: RouteConfig[] = [ }, { path: "status", - getComponent: () => StatusRoute, - prepare: () => { - StatusRoute.preload() - }, + Component: StatusRoute, query: graphql` query routes_StatusQuery($orderID: ID!) { order: commerceOrder(id: $orderID) { @@ -259,7 +230,7 @@ export const routes: RouteConfig[] = [ }) as any, { path: "*", - Component: props => { + Component: (props) => { return }, }, diff --git a/src/v2/Apps/Purchase/PurchaseApp.tsx b/src/v2/Apps/Purchase/PurchaseApp.tsx index c44959c2cc1..8545924299f 100644 --- a/src/v2/Apps/Purchase/PurchaseApp.tsx +++ b/src/v2/Apps/Purchase/PurchaseApp.tsx @@ -7,6 +7,7 @@ import { Title } from "react-head" import { createFragmentContainer, graphql } from "react-relay" import { userIsAdmin } from "v2/Utils/user" import { PurchaseHistoryFragmentContainer as PurchaseHistory } from "./Components/PurchaseHistory" +import { Spacer } from "@artsy/palette" export interface PurchaseAppProps { me: PurchaseApp_me @@ -20,6 +21,7 @@ export const PurchaseApp = (props: any) => { return ( My Orders | Artsy + ) @@ -29,13 +31,12 @@ export const PurchaseApp = (props: any) => { } } -export const PurchaseAppFragmentContainer = createFragmentContainer( - PurchaseApp, - { - me: graphql` - fragment PurchaseApp_me on Me { - ...PurchaseHistory_me - } - `, - } -) +const PurchaseAppFragmentContainer = createFragmentContainer(PurchaseApp, { + me: graphql` + fragment PurchaseApp_me on Me { + ...PurchaseHistory_me + } + `, +}) + +export default PurchaseAppFragmentContainer diff --git a/src/v2/Apps/Purchase/__tests__/PurchaseApp.jest.tsx b/src/v2/Apps/Purchase/__tests__/PurchaseApp.jest.tsx index 0f5d7c7b5f0..730fec26a69 100644 --- a/src/v2/Apps/Purchase/__tests__/PurchaseApp.jest.tsx +++ b/src/v2/Apps/Purchase/__tests__/PurchaseApp.jest.tsx @@ -9,7 +9,7 @@ import React from "react" import { HeadProvider } from "react-head" import { graphql } from "react-relay" import { PurchaseHistoryProps } from "../Components/PurchaseHistory" -import { PurchaseAppFragmentContainer } from "../PurchaseApp" +import PurchaseAppFragmentContainer from "../PurchaseApp" jest.unmock("react-relay") @@ -72,7 +72,7 @@ const render = (me: PurchaseAppTestQueryRawResponse["me"], user: User) => } } `, - wrapper: children => ( + wrapper: (children) => ( {children} @@ -126,10 +126,7 @@ describe("Purchase app", () => { const pagination = component.find("LargePagination") expect(pagination.length).toBe(1) expect(pagination.text()).toContain("1234...7") - pagination - .find("button") - .at(1) - .simulate("click") + pagination.find("button").at(1).simulate("click") expect(refetchSpy).toHaveBeenCalledTimes(1) expect(refetchSpy.mock.calls[0][0]).toEqual( expect.objectContaining({ first: 10, after: "NQ" }) diff --git a/src/v2/Apps/Purchase/routes.tsx b/src/v2/Apps/Purchase/routes.tsx index e61e828018f..b568de3130f 100644 --- a/src/v2/Apps/Purchase/routes.tsx +++ b/src/v2/Apps/Purchase/routes.tsx @@ -1,13 +1,16 @@ +import loadable from "@loadable/component" import { graphql } from "react-relay" - -// @ts-ignore import { RouteConfig } from "found" -import { PurchaseAppFragmentContainer as PurchaseApp } from "./PurchaseApp" + +const PurchasesApp = loadable(() => import("./PurchaseApp")) export const routes: RouteConfig[] = [ { path: "/user/purchases", - Component: PurchaseApp, + getComponent: () => PurchasesApp, + prepare: () => { + PurchasesApp.preload() + }, query: graphql` query routes_PurchaseQuery { me { diff --git a/src/v2/Apps/getAppRoutes.tsx b/src/v2/Apps/getAppRoutes.tsx index 8ad532cba2c..7d4a6fe272a 100644 --- a/src/v2/Apps/getAppRoutes.tsx +++ b/src/v2/Apps/getAppRoutes.tsx @@ -6,6 +6,7 @@ import { collectRoutes } from "v2/Apps/Collect/collectRoutes" import { conversationRoutes } from "v2/Apps/Conversation/routes" import { routes as identityVerificationRoutes } from "v2/Apps/IdentityVerification/routes" import { routes as orderRoutes } from "v2/Apps/Order/routes" +import { routes as purchasesRoutes } from "v2/Apps/Purchase/routes" import { routes as searchRoutes } from "v2/Apps/Search/routes" import { routes as viewingRoomRoutes } from "./ViewingRoom/routes" @@ -29,6 +30,9 @@ export function getAppRoutes(): RouteConfig[] { { routes: orderRoutes, }, + { + routes: purchasesRoutes, + }, { routes: searchRoutes, }, diff --git a/src/v2/Artsy/Analytics/trackingMiddleware.ts b/src/v2/Artsy/Analytics/trackingMiddleware.ts index a3d6ebb3dfd..8468d592040 100644 --- a/src/v2/Artsy/Analytics/trackingMiddleware.ts +++ b/src/v2/Artsy/Analytics/trackingMiddleware.ts @@ -17,7 +17,7 @@ interface TrackingMiddlewareOptions { } export function trackingMiddleware(options: TrackingMiddlewareOptions = {}) { - return store => next => action => { + return (store) => (next) => (action) => { const { excludePaths = [] } = options const { type, payload } = action @@ -26,7 +26,7 @@ export function trackingMiddleware(options: TrackingMiddlewareOptions = {}) { const { pathname } = payload const referrer = get( store.getState(), - state => + (state) => state.found.match.location.pathname + state.found.match.location.search ) @@ -39,7 +39,7 @@ export function trackingMiddleware(options: TrackingMiddlewareOptions = {}) { // TODO: Pass referrer over to Artwork page if A/B test passes // window.sd.routerReferrer = referrer - const foundExcludedPath = excludePaths.some(excludedPath => { + const foundExcludedPath = excludePaths.some((excludedPath) => { const matcher = match(excludedPath, { decode: decodeURIComponent }) const foundMatch = !!matcher(pathname) return foundMatch @@ -60,16 +60,6 @@ export function trackingMiddleware(options: TrackingMiddlewareOptions = {}) { trackingData.referrer = sd.APP_URL + referrer } - // TODO: Remove after EXPERIMENTAL_APP_SHELL AB test ends. - if ( - ["/collect", "/collections", "/collection/"].some(path => - pathname.includes(path) - ) && - referrer - ) { - trackingData.referrer = sd.APP_URL + referrer - } - /** * Store a global reference to the referrer. Since we're in an SPA * context we'll need to use this to track referrers statefully across @@ -90,11 +80,6 @@ export function trackingMiddleware(options: TrackingMiddlewareOptions = {}) { Marketo: false, }, }) - - // TODO: Remove after EXPERIMENTAL_APP_SHELL AB test ends. - // if (sd.CLIENT_NAVIGATION_V5) { - // trackExperimentViewed("client_navigation_v5", trackingData) - // } } // Reset timers that track time on page since we're tracking each order @@ -104,7 +89,7 @@ export function trackingMiddleware(options: TrackingMiddlewareOptions = {}) { window.desktopPageTimeTrackers if (desktopPageTimeTrackers) { - desktopPageTimeTrackers.forEach(tracker => { + desktopPageTimeTrackers.forEach((tracker) => { // No need to reset the tracker if we're on the same page. if (pathname !== tracker.path) { tracker.reset(pathname) diff --git a/src/v2/Artsy/Router/RenderStatus.tsx b/src/v2/Artsy/Router/RenderStatus.tsx index 551ac526a2b..ae1743de93f 100644 --- a/src/v2/Artsy/Router/RenderStatus.tsx +++ b/src/v2/Artsy/Router/RenderStatus.tsx @@ -13,7 +13,7 @@ import { PageLoader } from "./PageLoader" const logger = createLogger("Artsy/Router/Utils/RenderStatus") export const RenderPending = () => { - const { isFetching, setFetching, EXPERIMENTAL_APP_SHELL } = useSystemContext() + const { isFetching, setFetching } = useSystemContext() /** * First, set fetching to ensure that components that are listening for this @@ -26,43 +26,25 @@ export const RenderPending = () => { } if (isFetching) { - if (EXPERIMENTAL_APP_SHELL) { - return ( - <> - {null} - - - - - - ) - } else { - return ( - <> - {null} - - - ) - } + return ( + <> + {null} + + + + + + ) } } diff --git a/src/v2/Artsy/SystemContext.tsx b/src/v2/Artsy/SystemContext.tsx index 14f7ddd3085..63fb0ccfffe 100644 --- a/src/v2/Artsy/SystemContext.tsx +++ b/src/v2/Artsy/SystemContext.tsx @@ -76,9 +76,6 @@ export interface SystemContextProps extends SystemContextState { * Useful for passing arbitrary data from Force. */ injectedData?: any - - // TODO: Remove once A/B test completes - EXPERIMENTAL_APP_SHELL?: boolean } export const SystemContext = React.createContext({}) diff --git a/src/v2/Components/Modal/ErrorModal.tsx b/src/v2/Components/Modal/ErrorModal.tsx index 1f75f5d2759..0a0dd635348 100644 --- a/src/v2/Components/Modal/ErrorModal.tsx +++ b/src/v2/Components/Modal/ErrorModal.tsx @@ -15,9 +15,6 @@ interface ErrorModalProps { ctaAction?: () => void } -/** - * @deprecated use `Dialogs` and `injectDialogs` instead - */ export class ErrorModal extends React.Component { static defaultProps = { headerText: "An error occurred", diff --git a/src/v2/Components/NavBar/NavBar.tsx b/src/v2/Components/NavBar/NavBar.tsx index 193a8c75292..4e0b6e574f7 100644 --- a/src/v2/Components/NavBar/NavBar.tsx +++ b/src/v2/Components/NavBar/NavBar.tsx @@ -54,7 +54,7 @@ export const NavBar: React.FC = track( } )(() => { const { trackEvent } = useTracking() - const { mediator, user, EXPERIMENTAL_APP_SHELL } = useContext(SystemContext) + const { mediator, user } = useContext(SystemContext) const [showMobileMenu, toggleMobileNav] = useState(false) const xs = useMatchMedia(themeProps.mediaQueries.xs) const sm = useMatchMedia(themeProps.mediaQueries.sm) @@ -84,12 +84,8 @@ export const NavBar: React.FC = track( * TODO: Find a less naive way to check if route is in appshell */ const handleMobileNavClick = event => { - // FIXME: Remove once experimental A/B test completes - if (EXPERIMENTAL_APP_SHELL) { - // Includes /collect or /collections - if (event.target?.parentNode?.href?.includes("/collect")) { - toggleMobileNav(false) - } + if (event.target?.parentNode?.href?.includes("/collect")) { + toggleMobileNav(false) } } @@ -130,9 +126,7 @@ export const NavBar: React.FC = track( AnalyticsSchema.ContextModule.HeaderArtworksDropdown } onClick={() => { - if (EXPERIMENTAL_APP_SHELL) { - setIsVisible(false) - } + setIsVisible(false) }} /> @@ -165,9 +159,7 @@ export const NavBar: React.FC = track( AnalyticsSchema.ContextModule.HeaderArtistsDropdown } onClick={() => { - if (EXPERIMENTAL_APP_SHELL) { - setIsVisible(false) - } + setIsVisible(false) }} /> diff --git a/src/v2/Components/Search/SearchBar.tsx b/src/v2/Components/Search/SearchBar.tsx index 791401f9892..3c579c5d9c5 100644 --- a/src/v2/Components/Search/SearchBar.tsx +++ b/src/v2/Components/Search/SearchBar.tsx @@ -92,9 +92,6 @@ export class SearchBar extends Component { // this behaviour is acceptable. private userClickedOnDescendant: boolean - // TODO: Remove references once things go live - private enableExperimentalAppShell: boolean - state = { term: getSearchTerm(window.location), entityID: null, @@ -153,12 +150,6 @@ export class SearchBar extends Component { ) } - constructor(props) { - super(props) - - this.enableExperimentalAppShell = props.EXPERIMENTAL_APP_SHELL - } - componentDidMount() { this.throttledFetch = throttle(this.throttledFetch, 500, { leading: true, @@ -259,28 +250,23 @@ export class SearchBar extends Component { this.userClickedOnDescendant = true const newHref = displayType === "Artist" ? `${href}/works-for-sale` : href - if (this.enableExperimentalAppShell) { - if (this.props.router) { - // @ts-ignore (routeConfig not found; need to update DT types) - const routes = this.props.router.matcher.routeConfig - // @ts-ignore (matchRoutes not found; need to update DT types) - const isSupportedInRouter = !!this.props.router.matcher.matchRoutes( - routes, - newHref - ) - - // Check if url exists within the global router context - if (isSupportedInRouter) { - this.props.router.push(newHref) - this.onBlur({}) - } else { - window.location.assign(newHref) - } - // Outside of router context + if (this.props.router) { + // @ts-ignore (routeConfig not found; need to update DT types) + const routes = this.props.router.matcher.routeConfig + // @ts-ignore (matchRoutes not found; need to update DT types) + const isSupportedInRouter = !!this.props.router.matcher.matchRoutes( + routes, + newHref + ) + + // Check if url exists within the global router context + if (isSupportedInRouter) { + this.props.router.push(newHref) + this.onBlur({}) } else { window.location.assign(newHref) } - // New router not enabled + // Outside of router context } else { window.location.assign(newHref) } @@ -370,14 +356,12 @@ export class SearchBar extends Component { } // Clear input after submit - if (this.enableExperimentalAppShell) { - if (event.key === "Enter") { - setTimeout(() => { - this.setState({ - term: "", - }) + if (event.key === "Enter") { + setTimeout(() => { + this.setState({ + term: "", }) - } + }) } }, } @@ -427,16 +411,14 @@ export class SearchBar extends Component { itemScope itemType="http://schema.org/SearchAction" onSubmit={event => { - if (this.enableExperimentalAppShell) { - if (router) { - event.preventDefault() - router.push(`/search?term=${this.state.term}`) - this.onBlur(event) - } else { - console.error( - "[Components/Search/SearchBar] `router` instance not found." - ) - } + if (router) { + event.preventDefault() + router.push(`/search?term=${this.state.term}`) + this.onBlur(event) + } else { + console.error( + "[Components/Search/SearchBar] `router` instance not found." + ) } }} > diff --git a/src/v2/Utils/Hooks/useWindowSize.ts b/src/v2/Utils/Hooks/useWindowSize.ts index f7acc436a27..07a6a272f47 100644 --- a/src/v2/Utils/Hooks/useWindowSize.ts +++ b/src/v2/Utils/Hooks/useWindowSize.ts @@ -4,6 +4,10 @@ import { getViewportDimensions } from "v2/Utils/viewport" export const useWindowSize = () => { const [size, setSize] = useState({ width: 0, height: 0 }) + if (typeof window === "undefined") { + return size + } + useLayoutEffect(() => { function resize() { const { width, height } = getViewportDimensions() @@ -15,9 +19,5 @@ export const useWindowSize = () => { return () => window.removeEventListener("resize", resize) }, []) - if (typeof window === "undefined") { - return { width: 0, height: 0 } - } - return size } diff --git a/yarn.lock b/yarn.lock index 618b1da2509..4baeea528e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11295,6 +11295,11 @@ graceful-fs@4.2.3, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= +graphql-tag@^2.10.3: + version "2.10.3" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.3.tgz#ea1baba5eb8fc6339e4c4cf049dabe522b0edf03" + integrity sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA== + graphql-tools@4.0.3, graphql-tools@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-4.0.3.tgz#23b5cb52c519212b1b2e4630a361464396ad264b" @@ -13288,11 +13293,6 @@ jest-pnp-resolver@^1.2.1: resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== -jest-raw-loader@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz#ce9f56d54650f157c4a7d16d224ba5d613bcd626" - integrity sha1-zp9W1UZQ8VfEp9FtIkul1hO81iY= - jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" @@ -13403,6 +13403,11 @@ jest-styled-components@7.0.0-2: dependencies: css "^2.2.4" +jest-transform-graphql@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/jest-transform-graphql/-/jest-transform-graphql-2.1.0.tgz#903cb66bb27bc2772fd3e5dd4f7e9b57230f5829" + integrity sha1-kDy2a7J7wncv0+XdT36bVyMPWCk= + jest-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162"