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

mozilla / fx-private-relay / d4d9f278-d845-4992-8c81-4f3757c427a1

08 Sep 2025 02:07PM UTC coverage: 86.303% (-1.8%) from 88.121%
d4d9f278-d845-4992-8c81-4f3757c427a1

Pull #5842

circleci

joeherm
fix(deploy): Update CircleCI to use common Dockerfile for building frontend
Pull Request #5842: fix(deploy): Unify Dockerfiles

2744 of 3951 branches covered (69.45%)

Branch coverage included in aggregate %.

17910 of 19981 relevant lines covered (89.64%)

9.96 hits per line

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

65.0
/frontend/src/components/phones/dashboard/PhoneWelcomeView.tsx
1
import styles from "./PhoneWelcomeView.module.scss";
1✔
2
import SavingRelayContactImg from "./images/save-relay-as-a-contact.svg";
1✔
3
import SavingRelayContactDemoImg from "./images/save-relay-contact-demo.svg";
1✔
4
import ReplyingMessagesImg from "./images/reply-to-messages.svg";
1✔
5
import ReplyingMessagesDemoImg from "./images/reply-to-messages-demo.svg";
1✔
6
import BlockingMessagesImg from "./images/block-a-sender.svg";
1✔
7
import { ReactNode } from "react";
8
import { Button } from "../../Button";
1✔
9
import Image from "../../Image";
1✔
10
import { DismissalData } from "../../../hooks/localDismissal";
11
import { toast } from "react-toastify";
1✔
12
import { ProfileData } from "../../../hooks/api/profile";
13
import { useL10n } from "../../../hooks/l10n";
1✔
14
import { Localized } from "../../Localized";
1✔
15

16
type PhoneInstructionProps = {
17
  image: ReactNode;
18
  heading: string;
19
  body: ReactNode;
20
  demoHeading?: string;
21
  demoInput?: ReactNode;
22
  demoImage: ReactNode;
23
  alt: string;
24
};
25

26
const PhoneInstruction = (props: PhoneInstructionProps) => {
1✔
27
  return (
28
    <div className={styles["instruction-item"]}>
29
      {props.image}
30
      <h2>{props.heading}</h2>
31
      <p>{props.body}</p>
32
      <figure aria-hidden={props.alt === ""} className={styles["demo-wrapper"]}>
33
        <figcaption className={styles["demo-heading"]}>
34
          {props.demoHeading}
35
        </figcaption>
36
        <div
37
          aria-label={props.alt}
38
          className={styles["demo-input-wrapper"]}
39
          role="img"
40
        >
41
          {props.demoImage}
42
          <p className={styles["demo-input"]}>{props.demoInput}</p>
43
        </div>
44
      </figure>
45
    </div>
46
  );
47
};
48

49
type PhoneWelcomePageProps = {
50
  dismissal: {
51
    welcomeScreen: DismissalData;
52
    resendSMS: DismissalData;
53
  };
54
  onRequestContactCard: () => Promise<Response>;
55
  profile: ProfileData;
56
};
57

58
export const PhoneWelcomeView = (props: PhoneWelcomePageProps) => {
1✔
59
  const l10n = useL10n();
×
60

61
  // The unlocalized strings here are demo data
62
  const BlockSenderDemo = (
63
    <div className={styles["block-sender-wrapper"]}>
64
      <ul>
65
        <li>
66
          <span>
67
            <p>+1 (726) 777-7777</p>
68
            <p>
69
              {l10n.getString("phone-masking-splash-blocking-example-date")} -
70
              3:00pm
71
            </p>
72
          </span>
73
          <span>
74
            {l10n.getString("phone-masking-splash-blocking-example-unblock")}
75
          </span>
76
        </li>
77
        <li>
78
          <span>
79
            <p>John Doe</p>
80
            <p>08/23/2022 - 4:15pm</p>
81
          </span>
82
          <span>
83
            {l10n.getString("phone-masking-splash-blocking-example-block")}
84
          </span>
85
        </li>
86
      </ul>
87
    </div>
88
  );
89

90
  const DashboardBtn = (
91
    <Button
92
      className={styles["dashboard-btn"]}
93
      onClick={() => {
94
        props.dismissal.welcomeScreen.dismiss();
×
95
      }}
96
    >
97
      {l10n.getString("phone-masking-splash-continue-btn")}
98
    </Button>
99
  );
100

101
  return (
102
    <div className={styles["main-wrapper"]}>
103
      <div className={styles["main-heading"]}>
104
        <h1>{l10n.getString("phone-masking-splash-header")}</h1>
105
        <p>{l10n.getString("phone-masking-splash-subheading")}</p>
106
      </div>
107

108
      <div className={styles["phone-instructions-wrapper"]}>
109
        <PhoneInstruction
110
          alt=""
111
          image={<Image src={SavingRelayContactImg} alt="" />}
112
          heading={l10n.getString("phone-masking-splash-save-contact-title")}
113
          body={
114
            <>
115
              {l10n.getString("phone-masking-splash-save-contact-body")}
116
              <br />
117
              {!props.dismissal.resendSMS.isDismissed ? (
×
118
                <Button
119
                  onClick={async () => {
120
                    await props.onRequestContactCard();
×
121
                    toast(
×
122
                      l10n.getString(
123
                        "phone-banner-resend-welcome-sms-toast-msg",
124
                      ),
125
                      {
126
                        type: "success",
127
                      },
128
                    );
129
                    props.dismissal.resendSMS.dismiss();
×
130
                  }}
131
                  className={styles["welcome-text-cta"]}
132
                >
133
                  {l10n.getString("phone-masking-splash-save-contact-cta")}
134
                </Button>
135
              ) : null}
136
            </>
137
          }
138
          demoHeading={l10n.getString(
139
            "phone-masking-splash-save-contact-example",
140
          )}
141
          demoInput={
142
            <>
143
              {l10n.getString("phone-masking-splash-save-contact-example-text")}
144
              <div className={styles["relay-contact-icon"]}>FR</div>
145
            </>
146
          }
147
          demoImage={
148
            <div className={styles["demo-img"]}>
149
              <Image src={SavingRelayContactDemoImg} alt="" />
150
            </div>
151
          }
152
        />
153

154
        <PhoneInstruction
155
          alt=""
156
          image={<Image src={ReplyingMessagesImg} alt="" />}
157
          heading={l10n.getString("phone-masking-splash-replies-title")}
158
          body={l10n.getString("phone-masking-splash-replies-body")}
159
          demoHeading={l10n.getString("phone-masking-splash-replies-example")}
160
          demoInput={l10n.getString(
161
            "phone-masking-splash-replies-example-text",
162
          )}
163
          demoImage={
164
            <div className={styles["demo-img"]}>
165
              <Image src={ReplyingMessagesDemoImg} alt="" />
166
            </div>
167
          }
168
        />
169

170
        <PhoneInstruction
171
          alt=""
172
          image={<Image src={BlockingMessagesImg} alt="" />}
173
          heading={l10n.getString("phone-masking-splash-blocking-title")}
174
          body={
175
            <Localized
176
              id="phone-masking-splash-blocking-body"
177
              elems={{
178
                strong: <strong />,
179
              }}
180
            >
181
              <span></span>
182
            </Localized>
183
          }
184
          demoImage={BlockSenderDemo}
185
        />
186
      </div>
187
      {DashboardBtn}
188
    </div>
189
  );
190
};
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