• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / fx-private-relay / 8b39734c-31ce-4dbf-9b05-171797c18cae

02 Oct 2025 04:03PM UTC coverage: 88.815% (-0.05%) from 88.863%
8b39734c-31ce-4dbf-9b05-171797c18cae

Pull #5924

circleci

vpremamozilla
MPP-4348: propagate UTM params from landing page to SubPlat and Accounts URLs
Pull Request #5924: MPP-4348: propagate UTM params from landing page to SubPlat and Accounts URLs

2932 of 3953 branches covered (74.17%)

Branch coverage included in aggregate %.

13 of 21 new or added lines in 5 files covered. (61.9%)

4 existing lines in 3 files now uncovered.

18086 of 19712 relevant lines covered (91.75%)

11.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.05
/frontend/src/pages/phone.page.tsx
1
import { NextPage } from "next";
2
import { Layout } from "../components/layout/Layout";
1✔
3
import { useProfiles } from "../hooks/api/profile";
1✔
4
import { useUsers } from "../hooks/api/user";
1✔
5
import { PhoneOnboarding } from "../components/phones/onboarding/PhoneOnboarding";
1✔
6
import { useRelayNumber } from "../hooks/api/relayNumber";
1✔
7
import { useEffect, useState } from "react";
1✔
8
import { PhoneDashboard } from "../components/phones/dashboard/PhoneDashboard";
1✔
9
import { getRuntimeConfig } from "../config";
1✔
10
import { PurchasePhonesPlan } from "../components/phones/onboarding/PurchasePhonesPlan";
1✔
11
import { isVerified, useRealPhonesData } from "../hooks/api/realPhone";
1✔
12
import { DashboardSwitcher } from "../components/layout/navigation/DashboardSwitcher";
1✔
13
import { isFlagActive } from "../functions/waffle";
1✔
14
import { useRuntimeData } from "../hooks/api/runtimeData";
1✔
15
import { useRouter } from "next/router";
1✔
16
import { isPhonesAvailableInCountry } from "../functions/getPlan";
1✔
17
import { PhoneWelcomeView } from "../components/phones/dashboard/PhoneWelcomeView";
1✔
18
import { useLocalDismissal } from "../hooks/localDismissal";
1✔
19

20
const Phone: NextPage = () => {
1✔
21
  const runtimeData = useRuntimeData();
8✔
22
  const profileData = useProfiles();
8✔
23
  const profile = profileData.data?.[0];
8✔
24
  const router = useRouter();
8✔
25
  const userData = useUsers();
8✔
26
  const user = userData.data?.[0];
8✔
27
  const relayNumberData = useRelayNumber();
8✔
28
  const [isInOnboarding, setIsInOnboarding] = useState<boolean>();
8✔
29
  const welcomeScreenDismissal = useLocalDismissal(
8✔
30
    `phone-welcome-screen-${profile?.id}`,
31
  );
32

33
  const resendWelcomeSMSDismissal = useLocalDismissal(
8✔
34
    `resend-sms-banner-${profile?.id}`,
35
  );
36

37
  const realPhoneData = useRealPhonesData();
8✔
38
  // The user hasn't completed the onboarding yet if...
39
  const isNotSetup =
40
    // ...they haven't purchased the phone plan yet, or...
41
    profile?.has_phone === false ||
8✔
42
    // ...the API request for their Relay number has completed but returned no
43
    // result, or...
44
    (!relayNumberData.isValidating &&
45
      typeof relayNumberData.error === "undefined" &&
46
      typeof relayNumberData.data === "undefined") ||
47
    // ...there was a list of Relay numbers, but it was empty:
48
    relayNumberData.data?.length === 0;
49

50
  useEffect(() => {
8✔
51
    if (!runtimeData.data) {
8!
52
      return;
×
53
    }
54
    if (
8✔
55
      // Send the user to /premium if a phone subscription is not available in
56
      // the current country, and the user has not set it up before (possibly in
57
      // another country):
58
      !isPhonesAvailableInCountry(runtimeData.data) &&
16✔
59
      isNotSetup
60
    ) {
61
      router.push("/premium");
6✔
62
    }
63
  }, [runtimeData.data, router, isNotSetup]);
64

65
  useEffect(() => {
8✔
66
    if (
8✔
67
      typeof isInOnboarding === "undefined" &&
18✔
68
      Array.isArray(relayNumberData.data) &&
69
      relayNumberData.data.length === 0
70
    ) {
71
      setIsInOnboarding(true);
3✔
72
    }
73
  }, [isInOnboarding, relayNumberData]);
74

75
  if (!userData.isValidating && userData.error) {
8!
76
    const authParams =
NEW
77
      typeof window !== "undefined"
×
78
        ? encodeURIComponent(window.location.search.replace(/^\?/, ""))
79
        : "";
NEW
80
    document.location.assign(
×
81
      `${getRuntimeConfig().fxaLoginUrl}&auth_params=${authParams}`,
82
    );
83
  }
84

85
  if (!profile || !user || !relayNumberData.data || !runtimeData.data) {
8!
86
    // TODO: Show a loading spinner?
87
    return null;
×
88
  }
89

90
  // If the user has their phone subscription all set up, show the dashboard:
91
  const verifiedPhones = realPhoneData.data?.filter(isVerified) ?? [];
8!
92
  if (
8✔
93
    profile.has_phone &&
16✔
94
    !isInOnboarding &&
95
    verifiedPhones.length > 0 &&
96
    relayNumberData.data.length > 0
97
  ) {
98
    return (
99
      <Layout runtimeData={runtimeData.data}>
100
        <DashboardSwitcher />
101
        {/* Only show the welcome screen if the user hasn't seen it before */}
102
        {!welcomeScreenDismissal.isDismissed &&
4✔
103
        isFlagActive(runtimeData.data, "multi_replies") ? (
104
          <PhoneWelcomeView
×
105
            dismissal={{
106
              welcomeScreen: welcomeScreenDismissal,
107
              resendSMS: resendWelcomeSMSDismissal,
108
            }}
109
            onRequestContactCard={() => realPhoneData.resendWelcomeSMS()}
×
110
            profile={profile}
111
          />
112
        ) : (
113
          <PhoneDashboard
114
            dismissal={{
115
              resendSMS: resendWelcomeSMSDismissal,
116
            }}
117
            profile={profile}
118
            runtimeData={runtimeData.data}
119
            realPhone={verifiedPhones[0]}
120
            onRequestContactCard={() => realPhoneData.resendWelcomeSMS()}
×
121
          />
122
        )}
123
      </Layout>
124
    );
125
  }
126

127
  // If the user doesn't have a phone subscription already set up and can't
128
  // buy it in the country they're in, don't render anything; the `useEffect`
129
  // above will redirect the user to /premium
130
  if (!isPhonesAvailableInCountry(runtimeData.data)) {
6!
131
    return null;
6✔
132
  }
133

134
  // show the phone plan purchase page if the user has not purchased phone product
135
  if (!profile.has_phone) {
×
136
    return (
137
      <Layout runtimeData={runtimeData.data}>
138
        <DashboardSwitcher />
139
        <PurchasePhonesPlan runtimeData={runtimeData.data} />
140
      </Layout>
141
    );
142
  }
143

144
  // Otherwise start the onboarding process
145
  return (
146
    <Layout runtimeData={runtimeData.data}>
147
      <DashboardSwitcher />
148
      <PhoneOnboarding
149
        onComplete={() => setIsInOnboarding(false)}
×
150
        profile={profile}
151
        runtimeData={runtimeData.data}
152
      />
153
    </Layout>
154
  );
155
};
156

157
export default Phone;
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc