1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5import React from "react";
6import ReactDOM from "react-dom";
7import { MultiStageAboutWelcome } from "./components/MultiStageAboutWelcome";
8import { ReturnToAMO } from "./components/ReturnToAMO";
9
10class AboutWelcome extends React.PureComponent {
11  constructor(props) {
12    super(props);
13    this.state = { metricsFlowUri: null };
14    this.fetchFxAFlowUri = this.fetchFxAFlowUri.bind(this);
15  }
16
17  async fetchFxAFlowUri() {
18    this.setState({ metricsFlowUri: await window.AWGetFxAMetricsFlowURI() });
19  }
20
21  componentDidMount() {
22    if (!this.props.skipFxA) {
23      this.fetchFxAFlowUri();
24    }
25
26    // Rely on shared proton in-content styling for consistency.
27    if (this.props.design === "proton") {
28      const sheet = document.head.appendChild(document.createElement("link"));
29      sheet.rel = "stylesheet";
30      sheet.href = "chrome://global/skin/in-content/common.css";
31    }
32
33    // Record impression with performance data after allowing the page to load
34    const recordImpression = domState => {
35      const { domComplete, domInteractive } = performance
36        .getEntriesByType("navigation")
37        .pop();
38      window.AWSendEventTelemetry({
39        event: "IMPRESSION",
40        event_context: {
41          domComplete,
42          domInteractive,
43          mountStart: performance.getEntriesByName("mount").pop().startTime,
44          domState,
45          source: this.props.UTMTerm,
46          page: "about:welcome",
47        },
48        message_id: this.props.messageId,
49      });
50    };
51    if (document.readyState === "complete") {
52      // Page might have already triggered a load event because it waited for async data,
53      // e.g., attribution, so the dom load timing could be of a empty content
54      // with domState in telemetry captured as 'complete'
55      recordImpression(document.readyState);
56    } else {
57      window.addEventListener("load", () => recordImpression("load"), {
58        once: true,
59      });
60    }
61
62    // Captures user has seen about:welcome by setting
63    // firstrun.didSeeAboutWelcome pref to true and capturing welcome UI unique messageId
64    window.AWSendToParent("SET_WELCOME_MESSAGE_SEEN", this.props.messageId);
65  }
66
67  render() {
68    const { props } = this;
69    if (props.template === "return_to_amo") {
70      return (
71        <ReturnToAMO
72          message_id={props.messageId}
73          name={props.name}
74          url={props.url}
75          iconURL={props.iconURL}
76        />
77      );
78    }
79
80    return (
81      <MultiStageAboutWelcome
82        screens={props.screens}
83        metricsFlowUri={this.state.metricsFlowUri}
84        message_id={props.messageId}
85        utm_term={props.UTMTerm}
86        design={props.design}
87        transitions={props.transitions}
88        background_url={props.background_url}
89      />
90    );
91  }
92}
93
94// Computes messageId and UTMTerm info used in telemetry
95function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
96  let messageId =
97    welcomeContent.template === "return_to_amo"
98      ? "RTAMO_DEFAULT_WELCOME"
99      : "DEFAULT_ABOUTWELCOME";
100  let UTMTerm = "default";
101
102  if (welcomeContent.id) {
103    messageId = welcomeContent.id.toUpperCase();
104  }
105
106  if (experimentId && branchId) {
107    UTMTerm = `${experimentId}-${branchId}`.toLowerCase();
108  }
109  return {
110    messageId,
111    UTMTerm,
112  };
113}
114
115async function retrieveRenderContent() {
116  // Feature config includes RTAMO attribution data if exists
117  // else below data in order specified
118  // user prefs
119  // experiment data
120  // defaults
121  let featureConfig = await window.AWGetFeatureConfig();
122
123  let { messageId, UTMTerm } = ComputeTelemetryInfo(
124    featureConfig,
125    featureConfig.slug,
126    featureConfig.branch && featureConfig.branch.slug
127  );
128  return { featureConfig, messageId, UTMTerm };
129}
130
131async function mount() {
132  let {
133    featureConfig: aboutWelcomeProps,
134    messageId,
135    UTMTerm,
136  } = await retrieveRenderContent();
137  ReactDOM.render(
138    <AboutWelcome
139      messageId={messageId}
140      UTMTerm={UTMTerm}
141      {...aboutWelcomeProps}
142    />,
143    document.getElementById("root")
144  );
145}
146
147performance.mark("mount");
148mount();
149