Prefill notification email in Add Company wizard with the account's own email

Was always blank by default. Now prefilled from useCurrentUser() once it
loads (defaultValues can't do this since the query resolves after mount),
gated on the field not being dirty yet so it never clobbers something the
user already typed - still fully editable either way.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-05 21:07:32 -04:00
co-authored by Claude Sonnet 5
parent 4867793b66
commit 5b450f22cf
2 changed files with 49 additions and 3 deletions
+14 -3
View File
@@ -3,7 +3,7 @@
import { zodResolver } from "@hookform/resolvers/zod";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import { Suspense, useState } from "react";
import { Suspense, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { Loader2 } from "lucide-react";
import { z } from "zod";
@@ -13,7 +13,7 @@ import { api } from "@/lib/api-client";
import { useCompanies, useCreateCompany } from "@/hooks/use-companies";
import { useCreateNotificationDestination } from "@/hooks/use-notification-destinations";
import { useDiscoverCompany } from "@/hooks/use-discovery";
import { authErrorMessage, useSystemStatus } from "@/hooks/use-auth";
import { authErrorMessage, useCurrentUser, useSystemStatus } from "@/hooks/use-auth";
import {
FREQUENCY_LABELS,
MONITORING_FREQUENCIES,
@@ -126,6 +126,7 @@ function AddCompanyWizard() {
const createDestination = useCreateNotificationDestination();
const discoverCompany = useDiscoverCompany();
const { data: systemStatus } = useSystemStatus();
const { data: currentUser } = useCurrentUser();
const {
register,
@@ -135,7 +136,7 @@ function AddCompanyWizard() {
setValue,
getValues,
trigger,
formState: { errors },
formState: { errors, dirtyFields },
} = useForm<CompanyForm>({
resolver: zodResolver(companySchema),
defaultValues: {
@@ -146,6 +147,16 @@ function AddCompanyWizard() {
},
});
// Prefill with the account's own email once it loads - `defaultValues`
// can't do this since useCurrentUser resolves after the form has already
// mounted. Only sets it while the field is still untouched, so it never
// clobbers something the user already typed.
useEffect(() => {
if (currentUser?.email && !dirtyFields.notificationEmail) {
setValue("notificationEmail", currentUser.email);
}
}, [currentUser?.email, dirtyFields.notificationEmail, setValue]);
const frequencyType = watch("frequencyType");
const goNext = async () => {
@@ -51,6 +51,16 @@ const EXISTING_COMPANIES = [
},
];
const CURRENT_USER = {
id: "user-1",
email: "[email protected]",
display_name: "Team Person",
timezone: "America/New_York",
is_active: true,
is_admin: false,
auth_mode: "local",
};
function mockFetchImplementation(existingCompanies: unknown[] = []) {
return vi.fn().mockImplementation((url: string, init?: RequestInit) => {
const path = url.replace("http://localhost:8000", "");
@@ -60,6 +70,9 @@ function mockFetchImplementation(existingCompanies: unknown[] = []) {
if (path === "/api/v1/companies" && (!init?.method || init.method === "GET")) {
return Promise.resolve({ ok: true, status: 200, json: async () => existingCompanies });
}
if (path === "/api/v1/auth/me") {
return Promise.resolve({ ok: true, status: 200, json: async () => CURRENT_USER });
}
return Promise.resolve({ ok: false, status: 404, json: async () => ({ detail: "not found" }) });
});
}
@@ -128,4 +141,26 @@ describe("AddCompanyWizardPage", () => {
});
expect(screen.queryByText(/you might already be monitoring/i)).not.toBeInTheDocument();
});
it("pre-fills the notification email with the account's own email, still editable", async () => {
const user = userEvent.setup();
renderWithQueryClient(<AddCompanyWizardPage />);
await user.type(screen.getByLabelText("Company name"), "Acme Widgets");
await user.click(screen.getByRole("button", { name: /discover company/i }));
await waitFor(() => {
expect(screen.getByText(/here's what we found for/i)).toBeInTheDocument();
});
await user.click(screen.getByRole("button", { name: /^continue$/i })); // Review -> Schedule
await user.click(screen.getByRole("button", { name: /^continue$/i })); // Schedule -> Notifications
const email = (await screen.findByLabelText("Notification email")) as HTMLInputElement;
await waitFor(() => expect(email.value).toBe("[email protected]"));
// Still editable - prefilling must not lock the field.
await user.clear(email);
await user.type(email, "[email protected]");
expect(email.value).toBe("[email protected]");
});
});