Skip to content

Commit

Permalink
move through broker results in maintenance mode
Browse files Browse the repository at this point in the history
  • Loading branch information
codemist committed Dec 11, 2024
1 parent 717d73b commit 3bf4603
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 39 deletions.
1 change: 1 addition & 0 deletions locales/en/fix.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fix-flow-nav-security-recommendations = Security recommendations
guided-resolution-flow-exit = Return to dashboard
guided-resolution-flow-next-arrow = Go to next step
guided-resolution-flow-next-arrow-sub-step = Go to next result
guided-resolution-flow-step-navigation-label = Guided steps
# Celebration screens
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ import {
StepLink,
} from "../../../../../../../functions/server/getRelevantGuidedSteps";
import { useTelemetry } from "../../../../../../../hooks/useTelemetry";
import { TelemetryButton } from "../../../../../../../components/client/TelemetryButton";

export type FixViewProps = {
children: ReactNode;
subscriberEmails: string[];
data: StepDeterminationData;
nextStep: StepLink;
nextStep: StepLink | (() => void);
currentSection:
| "data-broker-profiles"
| "high-risk-data-breach"
Expand Down Expand Up @@ -95,22 +96,47 @@ export const FixView = (props: FixViewProps) => {
{!props.hideNavClose && navigationClose()}
<section className={styles.fixSection}>
<div className={styles.viewWrapper}>{props.children}</div>
{!props.hideNextNavigationRightArrow && (
<Link
className={`${styles.navArrow} ${styles.navArrowNext}`}
href={props.nextStep.href}
aria-label={l10n.getString("guided-resolution-flow-next-arrow")}
onClick={() => {
recordTelemetry("button", "click", {
button_id: "next_arrow",
});
}}
>
<Image alt="" src={ImageArrowRight} />
</Link>
)}
{!props.hideNextNavigationRightArrow &&
(isNextStepALink(props.nextStep) ? (
<Link
className={`${styles.navArrow} ${styles.navArrowNext}`}
href={props.nextStep.href}
aria-label={l10n.getString("guided-resolution-flow-next-arrow")}
onClick={() => {
recordTelemetry("button", "click", {
button_id: "next_arrow",
});
}}
>
<Image alt="" src={ImageArrowRight} />
</Link>
) : (
<TelemetryButton
className={`${styles.navArrow} ${styles.navArrowNext}`}
event={{
module: "button",
name: "click",
data: {
button_id: "go_to_next_result",
},
}}
variant="link"
onPress={props.nextStep}
aria-label={l10n.getString(
"guided-resolution-flow-next-arrow-sub-step",
)}
>
<Image alt="" src={ImageArrowRight} />
</TelemetryButton>
))}
</section>
</div>
</div>
);
};

function isNextStepALink(
nextStep: StepLink | (() => void),
): nextStep is StepLink {
return "href" in nextStep;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ import { axe } from "jest-axe";
import Meta, {
RemovalUnderMaintenanceViewStory,
} from "./RemovalUnderMaintenanceView.stories";

const mockedRouterPush = jest.fn();

jest.mock("../../../../../../../../../hooks/useTelemetry");
jest.mock("next/navigation", () => ({
useRouter: () => ({
push: mockedRouterPush,
Expand All @@ -23,6 +21,13 @@ jest.mock("next/navigation", () => ({
get: jest.fn(),
}),
}));
const mockedRecordTelemetry = jest.fn();

jest.mock("../../../../../../../../../hooks/useTelemetry", () => {
return {
useTelemetry: () => mockedRecordTelemetry,
};
});

describe("Removal under maintenance", () => {
it("passes the axe accessibility test suite", async () => {
Expand Down Expand Up @@ -122,3 +127,23 @@ describe("Removal under maintenance", () => {
expect(resolveButton).toHaveTextContent("Loading");
});
});

it("clicks the right arrow button to show the next step", async () => {
const user = userEvent.setup();
const RemovalUnderMaintenanceView = composeStory(
RemovalUnderMaintenanceViewStory,
Meta,
);
render(<RemovalUnderMaintenanceView />);
const resolveButton = screen.getByRole("button", {
name: "Go to next result",
});
await user.click(resolveButton);
expect(mockedRecordTelemetry).toHaveBeenCalledWith(
"button",
"click",
expect.objectContaining({
button_id: "go_to_next_result",
}),
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ export const RemovalUnderMaintenanceView = (props: Props) => {

// Not covered by tests; mostly side-effects. See test-coverage.md#mock-heavy
/* c8 ignore start */

function moveToNextAvailableStep() {
const currentResultIndex = props.data.results.findIndex(
(result) =>
result.onerep_scan_result_id ===
firstScanResultNotResolved.onerep_scan_result_id,
);

if (currentResultIndex < props.data.results.length - 1) {
// Move to the next unresolved result
const nextUnresolvedResult = props.data.results[currentResultIndex + 1];
setFirstScanResultNotResolved(nextUnresolvedResult);
} else {
// Redirect if no unresolved scan result remains
router.push(nextGuidedStep.href);
}
}

async function handleManualRemovalChange() {
setIsLoadingNextDataBroker(true);
try {
Expand All @@ -70,19 +88,7 @@ export const RemovalUnderMaintenanceView = (props: Props) => {
void confetti();

// Mark the current scan result as manually resolved
const currentResultIndex = props.data.results.findIndex(
(result) =>
result.onerep_scan_result_id ===
firstScanResultNotResolved.onerep_scan_result_id,
);

if (currentResultIndex < props.data.results.length - 1) {
const nextUnresolvedResult = props.data.results[currentResultIndex + 1];
setFirstScanResultNotResolved(nextUnresolvedResult);
} else {
// Redirect if no unresolved scan result remains
router.push(nextGuidedStep.href);
}
moveToNextAvailableStep();
} catch (error) {
console.error("Error occurred in handleManualRemovalChange:", error);
} finally {
Expand Down Expand Up @@ -398,7 +404,7 @@ export const RemovalUnderMaintenanceView = (props: Props) => {
return (
<FixView
subscriberEmails={props.subscriberEmails}
nextStep={nextGuidedStep}
nextStep={() => moveToNextAvailableStep()}
currentSection="data-broker-profiles"
data={props.stepDeterminationData}
hideProgressIndicator={detailedRemovalGuide}
Expand Down
10 changes: 4 additions & 6 deletions src/app/components/client/FixNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ export const Steps = (props: {
{label} {count > 0 && `(${count})`}
</div>
);

const dataBrokerStepCompleted =
hasCompletedStepSection(props.data, "Scan") &&
hasCompletedStepSection(props.data, "DataBrokerManualRemoval");
return (
<ul className={styles.steps}>
{isEligibleForStep(props.data, "Scan") && (
Expand All @@ -96,11 +98,7 @@ export const Steps = (props: {
}
className={`${styles.navigationItem} ${
props.currentSection === "data-broker-profiles" ? styles.active : ""
} ${
hasCompletedStepSection(props.data, "Scan")
? styles.isCompleted
: ""
}`}
} ${dataBrokerStepCompleted ? styles.isCompleted : ""}`}
>
<div className={styles.stepIcon}>
<StepImage data={props.data} section="Scan" />
Expand Down
4 changes: 2 additions & 2 deletions src/app/functions/server/getRelevantGuidedSteps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ export function hasCompletedStep(
): boolean {
if (stepId === "DataBrokerManualRemoval") {
return (
data.latestScanData?.results.every(
data.latestScanData?.results?.every(
(result) =>
result.broker_status === "removal_under_maintenance" &&
result.broker_status !== "removal_under_maintenance" ||
result.manually_resolved,
) ?? false
);
Expand Down

0 comments on commit 3bf4603

Please sign in to comment.