diff --git a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/Dashboard.test.tsx b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/Dashboard.test.tsx
index 2bc43a344bc..6b1c5e6d699 100644
--- a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/Dashboard.test.tsx
+++ b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/Dashboard.test.tsx
@@ -20,6 +20,11 @@ import Meta, {
DashboardNonUsNoBreaches,
DashboardNonUsUnresolvedBreaches,
DashboardNonUsResolvedBreaches,
+} from "./DashboardNonUSUsers.stories";
+import { useTelemetry } from "../../../../../../hooks/useTelemetry";
+import { deleteAllCookies } from "../../../../../../functions/client/deleteAllCookies";
+import { defaultExperimentData } from "../../../../../../../telemetry/generated/nimbus/experiments";
+import {
DashboardUsNoPremiumNoScanNoBreaches,
DashboardUsNoPremiumNoScanUnresolvedBreaches,
DashboardUsNoPremiumNoScanResolvedBreaches,
@@ -33,6 +38,11 @@ import Meta, {
DashboardUsNoPremiumResolvedScanNoBreaches,
DashboardUsNoPremiumResolvedScanUnresolvedBreaches,
DashboardUsNoPremiumResolvedScanResolvedBreaches,
+ DashboardUsNoPremiumScanInProgressNoBreaches,
+ DashboardUsNoPremiumScanInProgressUnresolvedBreaches,
+ DashboardUsNoPremiumScanInProgressResolvedBreaches,
+} from "./DashboardUSUsers.stories";
+import {
DashboardUsPremiumEmptyScanNoBreaches,
DashboardUsPremiumEmptyScanUnresolvedBreaches,
DashboardUsPremiumEmptyScanResolvedBreaches,
@@ -42,18 +52,12 @@ import Meta, {
DashboardUsPremiumResolvedScanNoBreaches,
DashboardUsPremiumResolvedScanUnresolvedBreaches,
DashboardUsPremiumResolvedScanResolvedBreaches,
- DashboardUsNoPremiumScanInProgressNoBreaches,
- DashboardUsNoPremiumScanInProgressUnresolvedBreaches,
- DashboardUsNoPremiumScanInProgressResolvedBreaches,
- DashboardUsPremiumScanInProgressNoBreaches,
- DashboardUsPremiumScanInProgressUnresolvedBreaches,
- DashboardUsPremiumScanInProgressResolvedBreaches,
DashboardInvalidPremiumUserNoScanResolvedBreaches,
DashboardUsPremiumManuallyResolvedScansNoBreaches,
-} from "./Dashboard.stories";
-import { useTelemetry } from "../../../../../../hooks/useTelemetry";
-import { deleteAllCookies } from "../../../../../../functions/client/deleteAllCookies";
-import { defaultExperimentData } from "../../../../../../../telemetry/generated/nimbus/experiments";
+ DashboardUsPremiumScanInProgressNoBreaches,
+ DashboardUsPremiumScanInProgressResolvedBreaches,
+ DashboardUsPremiumScanInProgressUnresolvedBreaches,
+} from "./DashboardPlusUsers.stories";
jest.mock("next/navigation", () => ({
useRouter: jest.fn(),
diff --git a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardNonUSUsers.stories.tsx b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardNonUSUsers.stories.tsx
new file mode 100644
index 00000000000..02498a32694
--- /dev/null
+++ b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardNonUSUsers.stories.tsx
@@ -0,0 +1,308 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { OnerepScanResultRow, OnerepScanRow } from "knex/types/tables";
+import { faker } from "@faker-js/faker";
+import { View as DashboardEl, TabType } from "./View";
+import { Shell } from "../../../../Shell";
+import { getL10n } from "../../../../../../functions/l10n/storybookAndJest";
+import {
+ createRandomScanResult,
+ createRandomBreach,
+ createUserWithPremiumSubscription,
+} from "../../../../../../../apiMocks/mockData";
+import { SubscriberBreach } from "../../../../../../../utils/subscriberBreaches";
+import { LatestOnerepScanData } from "../../../../../../../db/tables/onerep_scans";
+import { CountryCodeProvider } from "../../../../../../../contextProviders/country-code";
+import { SessionProvider } from "../../../../../../../contextProviders/session";
+import {
+ ExperimentData,
+ defaultExperimentData,
+} from "../../../../../../../telemetry/generated/nimbus/experiments";
+import { FeatureFlagName } from "../../../../../../../db/tables/featureFlags";
+
+const brokerOptions = {
+ "no-scan": "No scan started",
+ empty: "No scan results",
+ unresolved: "With unresolved scan results",
+ resolved: "All scan results resolved",
+ "scan-in-progress": "Scan is in progress",
+ "manually-resolved": "Manually resolved",
+};
+const breachOptions = {
+ empty: "No data breaches",
+ unresolved: "With unresolved data breaches",
+ resolved: "All data breaches resolved",
+};
+type DashboardWrapperProps = (
+ | {
+ countryCode: "us";
+ brokers: keyof typeof brokerOptions;
+ premium: boolean;
+ }
+ | {
+ countryCode: "nl";
+ }
+) & {
+ brokers: keyof typeof brokerOptions;
+ breaches: keyof typeof breachOptions;
+ elapsedTimeInDaysSinceInitialScan?: number;
+ totalNumberOfPerformedScans?: number;
+ activeTab?: TabType;
+ enabledFeatureFlags?: FeatureFlagName[];
+ experimentData?: ExperimentData;
+ hasFirstMonitoringScan?: boolean;
+ signInCount?: number;
+ autoOpenUpsellDialog?: boolean;
+};
+const DashboardWrapper = (props: DashboardWrapperProps) => {
+ const mockedResolvedBreach: SubscriberBreach = createRandomBreach({
+ dataClasses: [
+ "email-addresses",
+ "ip-addresses",
+ "phone-numbers",
+ "passwords",
+ "pins",
+ "social-security-numbers",
+ "partial-credit-card-data",
+ "security-questions-and-answers",
+ ],
+ addedDate: new Date("2023-06-18T14:48:00.000Z"),
+ dataClassesEffected: [
+ { "email-addresses": ["email1@gmail.com", "email2@gmail.com"] },
+ { "ip-addresses": 1 },
+ { "phone-numbers": 1 },
+ { passwords: 1 },
+ ],
+ isResolved: true,
+ });
+
+ const mockedUnresolvedBreach: SubscriberBreach = createRandomBreach({
+ dataClasses: ["email-addresses", "ip-addresses", "phone-numbers"],
+ addedDate: new Date("2023-06-18T14:48:00.000Z"),
+ dataClassesEffected: [
+ { "email-addresses": ["email1@gmail.com", "email2@gmail.com"] },
+ { "ip-addresses": 1 },
+ ],
+ isResolved: false,
+ });
+
+ let breaches: SubscriberBreach[] = [];
+ if (props.breaches === "resolved") {
+ breaches = [mockedResolvedBreach];
+ }
+ if (props.breaches === "unresolved") {
+ breaches = [mockedResolvedBreach, mockedUnresolvedBreach];
+ }
+
+ const mockedScan: OnerepScanRow = {
+ created_at: new Date(Date.UTC(1998, 2, 31)),
+ updated_at: new Date(Date.UTC(1998, 2, 31)),
+ id: 0,
+ onerep_profile_id: 0,
+ onerep_scan_id: 0,
+ onerep_scan_reason: "initial",
+ onerep_scan_status: "finished",
+ };
+
+ const mockedScanInProgress: OnerepScanRow = {
+ ...mockedScan,
+ onerep_scan_status: "in_progress",
+ };
+
+ const mockedInProgressScanResults: OnerepScanResultRow[] = [
+ createRandomScanResult({ status: "removed", manually_resolved: false }),
+ createRandomScanResult({
+ status: "waiting_for_verification",
+ manually_resolved: false,
+ }),
+ createRandomScanResult({
+ status: "optout_in_progress",
+ manually_resolved: false,
+ }),
+ ];
+
+ const mockedAllResolvedScanResults: OnerepScanResultRow[] = [
+ createRandomScanResult({ status: "removed", manually_resolved: false }),
+ createRandomScanResult({ status: "removed", manually_resolved: false }),
+ ];
+
+ const mockedUnresolvedScanResults: OnerepScanResultRow[] = [
+ ...mockedInProgressScanResults,
+ createRandomScanResult({ status: "new", manually_resolved: false }),
+ createRandomScanResult({ status: "new", manually_resolved: false }),
+ createRandomScanResult({ status: "new", manually_resolved: true }),
+ ];
+
+ const mockedManuallyResolvedScanResults: OnerepScanResultRow[] = [
+ createRandomScanResult({ status: "new", manually_resolved: true }),
+ createRandomScanResult({
+ status: "waiting_for_verification",
+ manually_resolved: true,
+ }),
+ createRandomScanResult({
+ status: "optout_in_progress",
+ manually_resolved: true,
+ }),
+ createRandomScanResult({ status: "removed", manually_resolved: true }),
+ ];
+
+ const scanData: LatestOnerepScanData = { scan: null, results: [] };
+ let scanCount = 0;
+
+ if (props.countryCode === "us") {
+ if (props.brokers && props.brokers !== "no-scan") {
+ const scanInProgress = props.brokers === "scan-in-progress";
+ scanData.scan = scanInProgress ? mockedScanInProgress : mockedScan;
+
+ if (scanInProgress) {
+ scanCount = 1;
+ }
+ if (props.brokers === "resolved") {
+ scanData.results = mockedAllResolvedScanResults;
+ }
+ if (props.brokers === "unresolved") {
+ scanData.results = mockedUnresolvedScanResults;
+ }
+
+ if (props.brokers === "manually-resolved") {
+ scanData.results = mockedManuallyResolvedScanResults;
+ }
+ }
+ }
+
+ const user = createUserWithPremiumSubscription();
+ if ((props.countryCode !== "us" || !props.premium) && user.fxa) {
+ user.fxa.subscriptions = [];
+ }
+
+ const mockedSession = {
+ expires: new Date().toISOString(),
+ user: user,
+ };
+
+ const mockedRemovalTimeEstimates = scanData.results
+ .map((scan) => ({
+ d: scan.data_broker,
+ t: faker.number.float({ min: 0, max: 200 }),
+ }))
+ .filter(() => Math.random() < 0.1);
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+const meta: Meta = {
+ title: "Pages/Logged in/Dashboard/Non US User",
+ component: DashboardWrapper,
+ argTypes: {
+ brokers: {
+ options: Object.keys(brokerOptions),
+ description: "Scan results",
+ control: {
+ type: "radio",
+ labels: brokerOptions,
+ },
+ },
+ breaches: {
+ options: Object.keys(breachOptions),
+ control: {
+ type: "radio",
+ labels: breachOptions,
+ },
+ },
+ elapsedTimeInDaysSinceInitialScan: {
+ name: "Days since initial scan",
+ control: {
+ type: "number",
+ },
+ },
+ hasFirstMonitoringScan: {
+ name: "Has first monitoring scan",
+ control: {
+ type: "boolean",
+ },
+ },
+ signInCount: {
+ name: "Sign-in count",
+ control: {
+ type: "number",
+ },
+ },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const DashboardNonUsNoBreaches: Story = {
+ name: "Non-US user, with 0 breaches",
+ args: {
+ countryCode: "nl",
+ breaches: "empty",
+ },
+};
+
+export const DashboardNonUsUnresolvedBreaches: Story = {
+ name: "Non-US user, with unresolved breaches",
+ args: {
+ countryCode: "nl",
+ breaches: "unresolved",
+ },
+};
+
+export const DashboardNonUsResolvedBreaches: Story = {
+ name: "Non-US user, with all breaches resolved",
+ args: {
+ countryCode: "nl",
+ breaches: "resolved",
+ },
+};
diff --git a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/Dashboard.stories.tsx b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardPlusUsers.stories.tsx
similarity index 76%
rename from src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/Dashboard.stories.tsx
rename to src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardPlusUsers.stories.tsx
index edd1db69390..22310ae744c 100644
--- a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/Dashboard.stories.tsx
+++ b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardPlusUsers.stories.tsx
@@ -241,7 +241,7 @@ const DashboardWrapper = (props: DashboardWrapperProps) => {
};
const meta: Meta = {
- title: "Pages/Logged in/Dashboard",
+ title: "Pages/Logged in/Dashboard/US User/Plus",
component: DashboardWrapper,
argTypes: {
brokers: {
@@ -279,164 +279,10 @@ const meta: Meta = {
},
},
};
+
export default meta;
type Story = StoryObj;
-export const DashboardNonUsNoBreaches: Story = {
- name: "Non-US user, with 0 breaches",
- args: {
- countryCode: "nl",
- breaches: "empty",
- },
-};
-
-export const DashboardNonUsUnresolvedBreaches: Story = {
- name: "Non-US user, with unresolved breaches",
- args: {
- countryCode: "nl",
- breaches: "unresolved",
- },
-};
-
-export const DashboardNonUsResolvedBreaches: Story = {
- name: "Non-US user, with all breaches resolved",
- args: {
- countryCode: "nl",
- breaches: "resolved",
- },
-};
-
-export const DashboardUsNoPremiumNoScanNoBreaches: Story = {
- name: "US user, without Premium, without scan, with 0 breaches",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "empty",
- brokers: "no-scan",
- },
-};
-
-export const DashboardUsNoPremiumNoScanUnresolvedBreaches: Story = {
- name: "US user, without Premium, without scan, with unresolved breaches",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "unresolved",
- brokers: "no-scan",
- },
-};
-
-export const DashboardUsNoPremiumNoScanResolvedBreaches: Story = {
- name: "US user, without Premium, without scan, with all breaches resolved",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "resolved",
- brokers: "no-scan",
- },
-};
-
-export const DashboardUsNoPremiumNoScanNoBreachesScanLimitReached: Story = {
- name: "US user, without Premium, without scan, with 0 breaches, Scan limit reached",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "empty",
- brokers: "no-scan",
- totalNumberOfPerformedScans: 280000,
- },
-};
-
-export const DashboardUsNoPremiumEmptyScanNoBreaches: Story = {
- name: "US user, without Premium, with 0 scan results, with 0 breaches",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "empty",
- brokers: "empty",
- },
-};
-
-export const DashboardUsNoPremiumEmptyScanUnresolvedBreaches: Story = {
- name: "US user, without Premium, with 0 scan results, with unresolved breaches",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "unresolved",
- brokers: "empty",
- },
-};
-
-export const DashboardUsNoPremiumEmptyScanResolvedBreaches: Story = {
- name: "US user, without Premium, with 0 scan results, with all breaches resolved",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "resolved",
- brokers: "empty",
- },
-};
-
-export const DashboardUsNoPremiumUnresolvedScanNoBreaches: Story = {
- name: "US user, without Premium, with unresolved scan results, with 0 breaches",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "empty",
- brokers: "unresolved",
- },
-};
-
-export const DashboardUsNoPremiumUnresolvedScanUnresolvedBreaches: Story = {
- name: "US user, without Premium, with unresolved scan results, with unresolved breaches",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "unresolved",
- brokers: "unresolved",
- },
-};
-
-export const DashboardUsNoPremiumUnresolvedScanResolvedBreaches: Story = {
- name: "US user, without Premium, with unresolved scan results, with all breaches resolved",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "resolved",
- brokers: "unresolved",
- },
-};
-
-export const DashboardUsNoPremiumResolvedScanNoBreaches: Story = {
- name: "US user, without Premium, with all scan results resolved, with 0 breaches",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "empty",
- brokers: "resolved",
- },
-};
-
-export const DashboardUsNoPremiumResolvedScanUnresolvedBreaches: Story = {
- name: "US user, without Premium, with all scan results resolved, with unresolved breaches",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "unresolved",
- brokers: "resolved",
- },
-};
-
-export const DashboardUsNoPremiumResolvedScanResolvedBreaches: Story = {
- name: "US user, without Premium, with all scan results resolved, with all breaches resolved",
- args: {
- countryCode: "us",
- premium: false,
- breaches: "resolved",
- brokers: "resolved",
- },
-};
-
export const DashboardUsPremiumEmptyScanNoBreaches: Story = {
name: "US user, with Premium, with 0 scan results, with 0 breaches",
args: {
diff --git a/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardUSUsers.stories.tsx b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardUSUsers.stories.tsx
new file mode 100644
index 00000000000..2aa3d652be2
--- /dev/null
+++ b/src/app/(proper_react)/(redesign)/(authenticated)/user/(dashboard)/dashboard/DashboardUSUsers.stories.tsx
@@ -0,0 +1,445 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { OnerepScanResultRow, OnerepScanRow } from "knex/types/tables";
+import { faker } from "@faker-js/faker";
+import { View as DashboardEl, TabType } from "./View";
+import { Shell } from "../../../../Shell";
+import { getL10n } from "../../../../../../functions/l10n/storybookAndJest";
+import {
+ createRandomScanResult,
+ createRandomBreach,
+ createUserWithPremiumSubscription,
+} from "../../../../../../../apiMocks/mockData";
+import { SubscriberBreach } from "../../../../../../../utils/subscriberBreaches";
+import { LatestOnerepScanData } from "../../../../../../../db/tables/onerep_scans";
+import { CountryCodeProvider } from "../../../../../../../contextProviders/country-code";
+import { SessionProvider } from "../../../../../../../contextProviders/session";
+import {
+ ExperimentData,
+ defaultExperimentData,
+} from "../../../../../../../telemetry/generated/nimbus/experiments";
+import { FeatureFlagName } from "../../../../../../../db/tables/featureFlags";
+
+const brokerOptions = {
+ "no-scan": "No scan started",
+ empty: "No scan results",
+ unresolved: "With unresolved scan results",
+ resolved: "All scan results resolved",
+ "scan-in-progress": "Scan is in progress",
+ "manually-resolved": "Manually resolved",
+};
+const breachOptions = {
+ empty: "No data breaches",
+ unresolved: "With unresolved data breaches",
+ resolved: "All data breaches resolved",
+};
+type DashboardWrapperProps = (
+ | {
+ countryCode: "us";
+ brokers: keyof typeof brokerOptions;
+ premium: boolean;
+ }
+ | {
+ countryCode: "nl";
+ }
+) & {
+ brokers: keyof typeof brokerOptions;
+ breaches: keyof typeof breachOptions;
+ elapsedTimeInDaysSinceInitialScan?: number;
+ totalNumberOfPerformedScans?: number;
+ activeTab?: TabType;
+ enabledFeatureFlags?: FeatureFlagName[];
+ experimentData?: ExperimentData;
+ hasFirstMonitoringScan?: boolean;
+ signInCount?: number;
+ autoOpenUpsellDialog?: boolean;
+};
+const DashboardWrapper = (props: DashboardWrapperProps) => {
+ const mockedResolvedBreach: SubscriberBreach = createRandomBreach({
+ dataClasses: [
+ "email-addresses",
+ "ip-addresses",
+ "phone-numbers",
+ "passwords",
+ "pins",
+ "social-security-numbers",
+ "partial-credit-card-data",
+ "security-questions-and-answers",
+ ],
+ addedDate: new Date("2023-06-18T14:48:00.000Z"),
+ dataClassesEffected: [
+ { "email-addresses": ["email1@gmail.com", "email2@gmail.com"] },
+ { "ip-addresses": 1 },
+ { "phone-numbers": 1 },
+ { passwords: 1 },
+ ],
+ isResolved: true,
+ });
+
+ const mockedUnresolvedBreach: SubscriberBreach = createRandomBreach({
+ dataClasses: ["email-addresses", "ip-addresses", "phone-numbers"],
+ addedDate: new Date("2023-06-18T14:48:00.000Z"),
+ dataClassesEffected: [
+ { "email-addresses": ["email1@gmail.com", "email2@gmail.com"] },
+ { "ip-addresses": 1 },
+ ],
+ isResolved: false,
+ });
+
+ let breaches: SubscriberBreach[] = [];
+ if (props.breaches === "resolved") {
+ breaches = [mockedResolvedBreach];
+ }
+ if (props.breaches === "unresolved") {
+ breaches = [mockedResolvedBreach, mockedUnresolvedBreach];
+ }
+
+ const mockedScan: OnerepScanRow = {
+ created_at: new Date(Date.UTC(1998, 2, 31)),
+ updated_at: new Date(Date.UTC(1998, 2, 31)),
+ id: 0,
+ onerep_profile_id: 0,
+ onerep_scan_id: 0,
+ onerep_scan_reason: "initial",
+ onerep_scan_status: "finished",
+ };
+
+ const mockedScanInProgress: OnerepScanRow = {
+ ...mockedScan,
+ onerep_scan_status: "in_progress",
+ };
+
+ const mockedInProgressScanResults: OnerepScanResultRow[] = [
+ createRandomScanResult({ status: "removed", manually_resolved: false }),
+ createRandomScanResult({
+ status: "waiting_for_verification",
+ manually_resolved: false,
+ }),
+ createRandomScanResult({
+ status: "optout_in_progress",
+ manually_resolved: false,
+ }),
+ ];
+
+ const mockedAllResolvedScanResults: OnerepScanResultRow[] = [
+ createRandomScanResult({ status: "removed", manually_resolved: false }),
+ createRandomScanResult({ status: "removed", manually_resolved: false }),
+ ];
+
+ const mockedUnresolvedScanResults: OnerepScanResultRow[] = [
+ ...mockedInProgressScanResults,
+ createRandomScanResult({ status: "new", manually_resolved: false }),
+ createRandomScanResult({ status: "new", manually_resolved: false }),
+ createRandomScanResult({ status: "new", manually_resolved: true }),
+ ];
+
+ const mockedManuallyResolvedScanResults: OnerepScanResultRow[] = [
+ createRandomScanResult({ status: "new", manually_resolved: true }),
+ createRandomScanResult({
+ status: "waiting_for_verification",
+ manually_resolved: true,
+ }),
+ createRandomScanResult({
+ status: "optout_in_progress",
+ manually_resolved: true,
+ }),
+ createRandomScanResult({ status: "removed", manually_resolved: true }),
+ ];
+
+ const scanData: LatestOnerepScanData = { scan: null, results: [] };
+ let scanCount = 0;
+
+ if (props.countryCode === "us") {
+ if (props.brokers && props.brokers !== "no-scan") {
+ const scanInProgress = props.brokers === "scan-in-progress";
+ scanData.scan = scanInProgress ? mockedScanInProgress : mockedScan;
+
+ if (scanInProgress) {
+ scanCount = 1;
+ }
+ if (props.brokers === "resolved") {
+ scanData.results = mockedAllResolvedScanResults;
+ }
+ if (props.brokers === "unresolved") {
+ scanData.results = mockedUnresolvedScanResults;
+ }
+
+ if (props.brokers === "manually-resolved") {
+ scanData.results = mockedManuallyResolvedScanResults;
+ }
+ }
+ }
+
+ const user = createUserWithPremiumSubscription();
+ if ((props.countryCode !== "us" || !props.premium) && user.fxa) {
+ user.fxa.subscriptions = [];
+ }
+
+ const mockedSession = {
+ expires: new Date().toISOString(),
+ user: user,
+ };
+
+ const mockedRemovalTimeEstimates = scanData.results
+ .map((scan) => ({
+ d: scan.data_broker,
+ t: faker.number.float({ min: 0, max: 200 }),
+ }))
+ .filter(() => Math.random() < 0.1);
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+const meta: Meta = {
+ title: "Pages/Logged in/Dashboard/US User/No Plus",
+ component: DashboardWrapper,
+ argTypes: {
+ brokers: {
+ options: Object.keys(brokerOptions),
+ description: "Scan results",
+ control: {
+ type: "radio",
+ labels: brokerOptions,
+ },
+ },
+ breaches: {
+ options: Object.keys(breachOptions),
+ control: {
+ type: "radio",
+ labels: breachOptions,
+ },
+ },
+ elapsedTimeInDaysSinceInitialScan: {
+ name: "Days since initial scan",
+ control: {
+ type: "number",
+ },
+ },
+ hasFirstMonitoringScan: {
+ name: "Has first monitoring scan",
+ control: {
+ type: "boolean",
+ },
+ },
+ signInCount: {
+ name: "Sign-in count",
+ control: {
+ type: "number",
+ },
+ },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const DashboardUsNoPremiumNoScanNoBreaches: Story = {
+ name: "US user, without Premium, without scan, with 0 breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "empty",
+ brokers: "no-scan",
+ },
+};
+
+export const DashboardUsNoPremiumNoScanUnresolvedBreaches: Story = {
+ name: "US user, without Premium, without scan, with unresolved breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "unresolved",
+ brokers: "no-scan",
+ },
+};
+
+export const DashboardUsNoPremiumNoScanResolvedBreaches: Story = {
+ name: "US user, without Premium, without scan, with all breaches resolved",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "resolved",
+ brokers: "no-scan",
+ },
+};
+
+export const DashboardUsNoPremiumNoScanNoBreachesScanLimitReached: Story = {
+ name: "US user, without Premium, without scan, with 0 breaches, Scan limit reached",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "empty",
+ brokers: "no-scan",
+ totalNumberOfPerformedScans: 280000,
+ },
+};
+
+export const DashboardUsNoPremiumEmptyScanNoBreaches: Story = {
+ name: "US user, without Premium, with 0 scan results, with 0 breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "empty",
+ brokers: "empty",
+ },
+};
+
+export const DashboardUsNoPremiumEmptyScanUnresolvedBreaches: Story = {
+ name: "US user, without Premium, with 0 scan results, with unresolved breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "unresolved",
+ brokers: "empty",
+ },
+};
+
+export const DashboardUsNoPremiumEmptyScanResolvedBreaches: Story = {
+ name: "US user, without Premium, with 0 scan results, with all breaches resolved",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "resolved",
+ brokers: "empty",
+ },
+};
+
+export const DashboardUsNoPremiumUnresolvedScanNoBreaches: Story = {
+ name: "US user, without Premium, with unresolved scan results, with 0 breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "empty",
+ brokers: "unresolved",
+ },
+};
+
+export const DashboardUsNoPremiumUnresolvedScanUnresolvedBreaches: Story = {
+ name: "US user, without Premium, with unresolved scan results, with unresolved breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "unresolved",
+ brokers: "unresolved",
+ },
+};
+
+export const DashboardUsNoPremiumUnresolvedScanResolvedBreaches: Story = {
+ name: "US user, without Premium, with unresolved scan results, with all breaches resolved",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "resolved",
+ brokers: "unresolved",
+ },
+};
+
+export const DashboardUsNoPremiumResolvedScanNoBreaches: Story = {
+ name: "US user, without Premium, with all scan results resolved, with 0 breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "empty",
+ brokers: "resolved",
+ },
+};
+
+export const DashboardUsNoPremiumResolvedScanUnresolvedBreaches: Story = {
+ name: "US user, without Premium, with all scan results resolved, with unresolved breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "unresolved",
+ brokers: "resolved",
+ },
+};
+
+export const DashboardUsNoPremiumResolvedScanResolvedBreaches: Story = {
+ name: "US user, without Premium, with all scan results resolved, with all breaches resolved",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "resolved",
+ brokers: "resolved",
+ },
+};
+
+export const DashboardUsNoPremiumScanInProgressNoBreaches: Story = {
+ name: "US user, without Premium, scan in progress, with no breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "empty",
+ brokers: "scan-in-progress",
+ },
+};
+
+export const DashboardUsNoPremiumScanInProgressUnresolvedBreaches: Story = {
+ name: "US user, without Premium, scan in progress, with unresolved breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "unresolved",
+ brokers: "scan-in-progress",
+ },
+};
+
+export const DashboardUsNoPremiumScanInProgressResolvedBreaches: Story = {
+ name: "US user, without Premium, scan in progress, with resolved breaches",
+ args: {
+ countryCode: "us",
+ premium: false,
+ breaches: "resolved",
+ brokers: "scan-in-progress",
+ },
+};
diff --git a/src/app/(proper_react)/(redesign)/(public)/MobileShell.stories.ts b/src/app/(proper_react)/(redesign)/(public)/MobileShell.stories.ts
new file mode 100644
index 00000000000..cc0dda1dafe
--- /dev/null
+++ b/src/app/(proper_react)/(redesign)/(public)/MobileShell.stories.ts
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { Session } from "next-auth";
+import { SerializedSubscriber } from "../../../../next-auth";
+
+import type { Meta, StoryObj } from "@storybook/react";
+import { MobileShell } from "../MobileShell";
+
+function createUser(): Session["user"] {
+ return {
+ email: "example@example.com",
+ fxa: {
+ locale: "us",
+ twoFactorAuthentication: false,
+ metricsEnabled: false,
+ avatar: "https://profile.stage.mozaws.net/v1/avatar/e",
+ avatarDefault: true,
+ subscriptions: ["monitor"],
+ },
+ subscriber: {
+ id: 42,
+ } as SerializedSubscriber,
+ };
+}
+
+const mockedSession = {
+ expires: new Date().toISOString(),
+ user: createUser(),
+};
+
+const meta: Meta = {
+ title: "Layout/Mobile Shell",
+ component: MobileShell,
+};
+export default meta;
+type Story = StoryObj;
+
+export const MobileShellStory: Story = {
+ args: {
+ countryCode: "us",
+ session: mockedSession,
+ },
+};
diff --git a/src/app/(proper_react)/(redesign)/(public)/PublicShell.stories.ts b/src/app/(proper_react)/(redesign)/(public)/PublicShell.stories.ts
new file mode 100644
index 00000000000..87dd3f7ae6f
--- /dev/null
+++ b/src/app/(proper_react)/(redesign)/(public)/PublicShell.stories.ts
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { PublicShell } from "./PublicShell";
+import { getL10n } from "../../../functions/l10n/storybookAndJest";
+
+const meta: Meta = {
+ title: "Layout/Public Shell",
+ component: PublicShell,
+};
+export default meta;
+type Story = StoryObj;
+
+export const PublicShellStory: Story = {
+ args: {
+ countryCode: "us",
+ l10n: getL10n("en"),
+ },
+};
diff --git a/src/app/components/client/exposure_card/ExposureCard.stories.tsx b/src/app/components/client/exposure_card/ExposureCard.stories.tsx
index 12217af9483..4aac589328e 100644
--- a/src/app/components/client/exposure_card/ExposureCard.stories.tsx
+++ b/src/app/components/client/exposure_card/ExposureCard.stories.tsx
@@ -13,7 +13,7 @@ import {
import { defaultExperimentData } from "../../../../telemetry/generated/nimbus/experiments";
const meta: Meta = {
- title: "ExposureCard",
+ title: "Dashboard/Exposures/Exposure Card",
component: ExposureCard,
tags: ["autodocs"],
args: {
diff --git a/src/app/components/client/stories/Button.stories.ts b/src/app/components/client/stories/Button.stories.ts
index c3c2e8f36d4..5f03aca8ef9 100644
--- a/src/app/components/client/stories/Button.stories.ts
+++ b/src/app/components/client/stories/Button.stories.ts
@@ -8,7 +8,7 @@ import { Button } from "../Button";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "Button",
+ title: "Design Systems/Atoms/Button",
component: Button,
};
export default meta;
diff --git a/src/app/components/client/stories/Chart.stories.ts b/src/app/components/client/stories/Chart.stories.ts
index e1748c19058..a8fed6811ed 100644
--- a/src/app/components/client/stories/Chart.stories.ts
+++ b/src/app/components/client/stories/Chart.stories.ts
@@ -8,7 +8,7 @@ import { DoughnutChart } from "../Chart";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "Charts",
+ title: "Dashboard/TopBanner/Charts",
component: DoughnutChart,
};
export default meta;
diff --git a/src/app/components/client/stories/Checkbox.stories.ts b/src/app/components/client/stories/Checkbox.stories.ts
new file mode 100644
index 00000000000..831c9426b6d
--- /dev/null
+++ b/src/app/components/client/stories/Checkbox.stories.ts
@@ -0,0 +1,71 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { Button } from "../Button";
+
+// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
+const meta: Meta = {
+ title: "Design Systems/Atoms/Checkbox",
+ component: Button,
+};
+export default meta;
+type Story = StoryObj;
+
+export const Primary: Story = {
+ args: {
+ variant: "primary",
+ children: "Button",
+ destructive: false,
+ small: false,
+ },
+};
+
+export const Secondary: Story = {
+ args: {
+ variant: "secondary",
+ children: "Button",
+ },
+};
+
+export const PrimarySmall: Story = {
+ args: {
+ variant: "primary",
+ children: "Button",
+ small: true,
+ },
+};
+
+export const PrimaryWide: Story = {
+ args: {
+ variant: "primary",
+ children: "Button",
+ wide: true,
+ },
+};
+
+export const SecondarySmall: Story = {
+ args: {
+ variant: "secondary",
+ children: "Button",
+ small: true,
+ },
+};
+
+export const PrimaryLink: Story = {
+ args: {
+ variant: "primary",
+ children: "Button",
+ href: "/",
+ },
+};
+
+export const SecondaryLink: Story = {
+ args: {
+ variant: "secondary",
+ children: "Button",
+ href: "/",
+ },
+};
diff --git a/src/app/components/client/stories/ComboBox.stories.tsx b/src/app/components/client/stories/ComboBox.stories.tsx
index 2a5ed43d24c..14e33a10bf3 100644
--- a/src/app/components/client/stories/ComboBox.stories.tsx
+++ b/src/app/components/client/stories/ComboBox.stories.tsx
@@ -20,7 +20,7 @@ const items: Array = [
];
const meta: Meta = {
- title: "ComboBox",
+ title: "Design Systems/Atoms/ComboBox",
component: ComboBox,
};
export default meta;
diff --git a/src/app/components/client/stories/CsatSurvey.stories.ts b/src/app/components/client/stories/CsatSurvey.stories.ts
index 3e5453db77c..889fde8d679 100644
--- a/src/app/components/client/stories/CsatSurvey.stories.ts
+++ b/src/app/components/client/stories/CsatSurvey.stories.ts
@@ -9,7 +9,7 @@ import { createUserWithPremiumSubscription } from "../../../../apiMocks/mockData
import { defaultExperimentData } from "../../../../telemetry/generated/nimbus/experiments";
const meta: Meta = {
- title: "CsatSurvey",
+ title: "Misc/CsatSurvey",
component: CsatSurvey,
};
export default meta;
diff --git a/src/app/components/client/stories/ExposuresFilter.stories.ts b/src/app/components/client/stories/ExposuresFilter.stories.ts
index a7c0de228db..c64ed7a806c 100644
--- a/src/app/components/client/stories/ExposuresFilter.stories.ts
+++ b/src/app/components/client/stories/ExposuresFilter.stories.ts
@@ -7,7 +7,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import { ExposuresFilter, FilterState } from "../ExposuresFilter";
const meta: Meta = {
- title: "ExposuresFilter",
+ title: "Dashboard/Exposures/FilterBar",
component: ExposuresFilter,
};
export default meta;
diff --git a/src/app/components/client/stories/InputField.stories.ts b/src/app/components/client/stories/InputField.stories.ts
index 402684871c9..59e1a7666a1 100644
--- a/src/app/components/client/stories/InputField.stories.ts
+++ b/src/app/components/client/stories/InputField.stories.ts
@@ -7,7 +7,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import { InputField } from "../InputField";
const meta: Meta = {
- title: "InputField",
+ title: "Design Systems/Molecules/Input Field",
component: InputField,
};
export default meta;
diff --git a/src/app/components/client/stories/PetitionBanner.stories.ts b/src/app/components/client/stories/PetitionBanner.stories.ts
index 5a46986b6cb..177f13216ce 100644
--- a/src/app/components/client/stories/PetitionBanner.stories.ts
+++ b/src/app/components/client/stories/PetitionBanner.stories.ts
@@ -7,7 +7,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import { PetitionBanner } from "../PetitionBanner";
const meta: Meta = {
- title: "PetitionBanner",
+ title: "Misc/PetitionBanner",
component: PetitionBanner,
};
export default meta;
diff --git a/src/app/components/client/stories/ProgressBar.stories.tsx b/src/app/components/client/stories/ProgressBar.stories.tsx
index 64b1057e14f..9f065e91cf1 100644
--- a/src/app/components/client/stories/ProgressBar.stories.tsx
+++ b/src/app/components/client/stories/ProgressBar.stories.tsx
@@ -21,7 +21,7 @@ const ProgressBarDemo = (props: ProgressBarProps) => {
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "Progress bar",
+ title: "Welcome Scan/ProgressBar",
component: ProgressBarDemo,
};
export default meta;
diff --git a/src/app/components/client/stories/ProgressCard.stories.ts b/src/app/components/client/stories/ProgressCard.stories.ts
index 4ca1cd80dc6..ddff6f5663d 100644
--- a/src/app/components/client/stories/ProgressCard.stories.ts
+++ b/src/app/components/client/stories/ProgressCard.stories.ts
@@ -8,7 +8,7 @@ import { ProgressCard } from "../ProgressCard";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "ProgressCard",
+ title: "Dashboard/Top Banner/Progress Infographic",
component: ProgressCard,
};
export default meta;
diff --git a/src/app/components/client/stories/Radio.stories.ts b/src/app/components/client/stories/Radio.stories.ts
new file mode 100644
index 00000000000..8fb77141094
--- /dev/null
+++ b/src/app/components/client/stories/Radio.stories.ts
@@ -0,0 +1,71 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { Button } from "../Button";
+
+// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
+const meta: Meta = {
+ title: "Design Systems/Atoms/Radio",
+ component: Button,
+};
+export default meta;
+type Story = StoryObj;
+
+export const Primary: Story = {
+ args: {
+ variant: "primary",
+ children: "Button",
+ destructive: false,
+ small: false,
+ },
+};
+
+export const Secondary: Story = {
+ args: {
+ variant: "secondary",
+ children: "Button",
+ },
+};
+
+export const PrimarySmall: Story = {
+ args: {
+ variant: "primary",
+ children: "Button",
+ small: true,
+ },
+};
+
+export const PrimaryWide: Story = {
+ args: {
+ variant: "primary",
+ children: "Button",
+ wide: true,
+ },
+};
+
+export const SecondarySmall: Story = {
+ args: {
+ variant: "secondary",
+ children: "Button",
+ small: true,
+ },
+};
+
+export const PrimaryLink: Story = {
+ args: {
+ variant: "primary",
+ children: "Button",
+ href: "/",
+ },
+};
+
+export const SecondaryLink: Story = {
+ args: {
+ variant: "secondary",
+ children: "Button",
+ href: "/",
+ },
+};
diff --git a/src/app/components/client/stories/TabList.stories.ts b/src/app/components/client/stories/TabList.stories.ts
index f2d18fd1907..d3d316e2b04 100644
--- a/src/app/components/client/stories/TabList.stories.ts
+++ b/src/app/components/client/stories/TabList.stories.ts
@@ -7,7 +7,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import { TabList } from "../TabList";
const meta: Meta = {
- title: "TabList",
+ title: "Design Systems/Molecules/TabList",
component: TabList,
};
export default meta;
diff --git a/src/app/components/client/stories/UpsellCta.stories.tsx b/src/app/components/client/stories/UpsellCta.stories.tsx
index 2cc9c70536d..801480cdf9e 100644
--- a/src/app/components/client/stories/UpsellCta.stories.tsx
+++ b/src/app/components/client/stories/UpsellCta.stories.tsx
@@ -58,7 +58,7 @@ const UpsellCtaWrapper = (props: UpsellCtaWrapperProps) => {
};
const meta: Meta = {
- title: "Upsell CTA",
+ title: "Design Systems/Atoms/Misc/Upsell CTA",
component: UpsellCtaWrapper,
};
export default meta;
diff --git a/src/app/components/client/toolbar/AppPicker.stories.ts b/src/app/components/client/toolbar/AppPicker.stories.ts
index 890875b7510..96b84c99ea8 100644
--- a/src/app/components/client/toolbar/AppPicker.stories.ts
+++ b/src/app/components/client/toolbar/AppPicker.stories.ts
@@ -6,7 +6,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import { AppPicker } from "./AppPicker";
const meta: Meta = {
- title: "Toolbar",
+ title: "Layout/Navigation/Bento App Picker",
component: AppPicker,
};
diff --git a/src/app/components/client/toolbar/UserMenu.stories.ts b/src/app/components/client/toolbar/UserMenu.stories.ts
index 48cc9d057cb..5cee50c7349 100644
--- a/src/app/components/client/toolbar/UserMenu.stories.ts
+++ b/src/app/components/client/toolbar/UserMenu.stories.ts
@@ -6,7 +6,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import { UserMenu } from "./UserMenu";
const meta: Meta = {
- title: "Toolbar",
+ title: "Layout/Navigation/Toolbar",
component: UserMenu,
};
export default meta;
diff --git a/src/app/components/server/stories/StatusPill.stories.ts b/src/app/components/server/stories/StatusPill.stories.ts
index 7d78adf207f..e8a9b125f46 100644
--- a/src/app/components/server/stories/StatusPill.stories.ts
+++ b/src/app/components/server/stories/StatusPill.stories.ts
@@ -8,7 +8,7 @@ import { StatusPill } from "../StatusPill";
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta = {
- title: "Status Pill",
+ title: "Design Systems/Atoms/Pill",
component: StatusPill,
};
export default meta;