mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 13:47:19 +08:00
feat: add PostHog tracking for enterprise lead form submission
- Add trackEnterpriseLeadFormSubmitted function to use-tracking.ts - Track form data on submit: requestType (saas/self-hosted), name, company, email, message - Add inline styles to onboarding-layout.tsx to prevent FOUC - Add 4 new tests for tracking behavior (25 total tests) PostHog event: 'enterprise_lead_form_submitted' Properties: request_type, name, company, email, message, plus common properties Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
@@ -14,6 +14,14 @@ vi.mock("react-router", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
// Mock useTracking
|
||||
const mockTrackEnterpriseLeadFormSubmitted = vi.fn();
|
||||
vi.mock("#/hooks/use-tracking", () => ({
|
||||
useTracking: () => ({
|
||||
trackEnterpriseLeadFormSubmitted: mockTrackEnterpriseLeadFormSubmitted,
|
||||
}),
|
||||
}));
|
||||
|
||||
describe("InformationRequestForm", () => {
|
||||
const defaultProps = {
|
||||
requestType: "saas" as RequestType,
|
||||
@@ -190,6 +198,16 @@ describe("InformationRequestForm", () => {
|
||||
expect(mockNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not call tracking when form is submitted with empty fields", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithRouter();
|
||||
|
||||
const submitButton = screen.getByRole("button", { name: "ENTERPRISE$FORM_SUBMIT" });
|
||||
await user.click(submitButton);
|
||||
|
||||
expect(mockTrackEnterpriseLeadFormSubmitted).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should navigate to homepage with modal state when form is submitted with all fields filled", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithRouter();
|
||||
@@ -207,6 +225,70 @@ describe("InformationRequestForm", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should call tracking with form data when form is submitted successfully", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithRouter({ ...defaultProps, requestType: "saas" });
|
||||
|
||||
await user.type(screen.getByTestId("form-input-name"), "John Doe");
|
||||
await user.type(screen.getByTestId("form-input-company"), "Acme Inc");
|
||||
await user.type(screen.getByTestId("form-input-email"), "john@example.com");
|
||||
await user.type(screen.getByTestId("form-input-message"), "Hello world");
|
||||
|
||||
const submitButton = screen.getByRole("button", { name: "ENTERPRISE$FORM_SUBMIT" });
|
||||
await user.click(submitButton);
|
||||
|
||||
expect(mockTrackEnterpriseLeadFormSubmitted).toHaveBeenCalledTimes(1);
|
||||
expect(mockTrackEnterpriseLeadFormSubmitted).toHaveBeenCalledWith({
|
||||
requestType: "saas",
|
||||
name: "John Doe",
|
||||
company: "Acme Inc",
|
||||
email: "john@example.com",
|
||||
message: "Hello world",
|
||||
});
|
||||
});
|
||||
|
||||
it("should call tracking with self-hosted request type", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithRouter({ ...defaultProps, requestType: "self-hosted" });
|
||||
|
||||
await user.type(screen.getByTestId("form-input-name"), "Jane Smith");
|
||||
await user.type(screen.getByTestId("form-input-company"), "Tech Corp");
|
||||
await user.type(screen.getByTestId("form-input-email"), "jane@techcorp.com");
|
||||
await user.type(screen.getByTestId("form-input-message"), "Interested in self-hosted");
|
||||
|
||||
const submitButton = screen.getByRole("button", { name: "ENTERPRISE$FORM_SUBMIT" });
|
||||
await user.click(submitButton);
|
||||
|
||||
expect(mockTrackEnterpriseLeadFormSubmitted).toHaveBeenCalledWith({
|
||||
requestType: "self-hosted",
|
||||
name: "Jane Smith",
|
||||
company: "Tech Corp",
|
||||
email: "jane@techcorp.com",
|
||||
message: "Interested in self-hosted",
|
||||
});
|
||||
});
|
||||
|
||||
it("should trim whitespace from form fields before tracking", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithRouter();
|
||||
|
||||
await user.type(screen.getByTestId("form-input-name"), " John Doe ");
|
||||
await user.type(screen.getByTestId("form-input-company"), " Acme Inc ");
|
||||
await user.type(screen.getByTestId("form-input-email"), " john@example.com ");
|
||||
await user.type(screen.getByTestId("form-input-message"), " Hello world ");
|
||||
|
||||
const submitButton = screen.getByRole("button", { name: "ENTERPRISE$FORM_SUBMIT" });
|
||||
await user.click(submitButton);
|
||||
|
||||
expect(mockTrackEnterpriseLeadFormSubmitted).toHaveBeenCalledWith({
|
||||
requestType: "saas",
|
||||
name: "John Doe",
|
||||
company: "Acme Inc",
|
||||
email: "john@example.com",
|
||||
message: "Hello world",
|
||||
});
|
||||
});
|
||||
|
||||
it("should have valid aria-invalid state when field has value", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithRouter();
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { useTracking } from "#/hooks/use-tracking";
|
||||
import { Card } from "#/ui/card";
|
||||
import { Text } from "#/ui/typography";
|
||||
import { FormInput } from "./form-input";
|
||||
@@ -22,6 +23,7 @@ export function InformationRequestForm({
|
||||
}: InformationRequestFormProps) {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const { trackEnterpriseLeadFormSubmitted } = useTracking();
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
company: "",
|
||||
@@ -46,6 +48,15 @@ export function InformationRequestForm({
|
||||
}
|
||||
|
||||
// TODO: Implement actual form submission API call
|
||||
// Track form submission in PostHog
|
||||
trackEnterpriseLeadFormSubmitted({
|
||||
requestType,
|
||||
name: formData.name.trim(),
|
||||
company: formData.company.trim(),
|
||||
email: formData.email.trim(),
|
||||
message: formData.message.trim(),
|
||||
});
|
||||
|
||||
// Navigate to homepage with state to show confirmation modal
|
||||
navigate("/", { state: { showRequestSubmittedModal: true } });
|
||||
};
|
||||
|
||||
@@ -129,6 +129,29 @@ export const useTracking = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const trackEnterpriseLeadFormSubmitted = ({
|
||||
requestType,
|
||||
name,
|
||||
company,
|
||||
email,
|
||||
message,
|
||||
}: {
|
||||
requestType: "saas" | "self-hosted";
|
||||
name: string;
|
||||
company: string;
|
||||
email: string;
|
||||
message: string;
|
||||
}) => {
|
||||
posthog.capture("enterprise_lead_form_submitted", {
|
||||
request_type: requestType,
|
||||
name,
|
||||
company,
|
||||
email,
|
||||
message,
|
||||
...commonProperties,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
trackLoginButtonClick,
|
||||
trackConversationCreated,
|
||||
@@ -142,5 +165,6 @@ export const useTracking = () => {
|
||||
trackAddTeamMembersButtonClick,
|
||||
trackOnboardingCompleted,
|
||||
trackSaasSelfhostedInquiry,
|
||||
trackEnterpriseLeadFormSubmitted,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user