From ae7712238eb9a8e6e12b4039a9fdb358109cbb68 Mon Sep 17 00:00:00 2001 From: Ben Senescu <44480372+bensenescu@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:38:08 -0400 Subject: [PATCH] refactor: use TanStack Form everywhere (#49) * refactor: move lighthouse audits to dataforseo (#43) * refactor: move lighthouse audits to dataforseo * chore: remove obsolete audit settings modal * refactor: rename psi flows to lighthouse * save * refactor: simplify audit lighthouse storage flow * fix: separate lighthouse metrics from actionable audits * refactor: remove redundant audit project inputs * feat: redesign lighthouse issues screen with score gauges and table layout Replace flat score cards with circular SVG gauges, condense metrics into a compact grid, and switch issue list from cards to an expandable table with fixed column widths. * test: harden lighthouse regression coverage * fix: restore project-scoped audit inputs * refactor: simplify lighthouse payload handling * refactor: inline lighthouse server handlers * refactor: share audit workflow types * refactor: simplify lighthouse payload flows * save * refactor: drop project pagespeed api key * fix: restore lighthouse issues loading with resilient project context * fix: restore audit issues back navigation * refactor: simplify project context and lighthouse error handling * fix: tolerate DataForSEO lighthouse payload drift * refactor: route audit lighthouse through dataforseo client --------- * refactor: unify app forms with TanStack Form Replace bespoke field and submit error state so validation, async submit handling, and router-synced inputs behave consistently across the app. * fix: remove dead code from ci check * fix: delay required form errors until input interaction * fix: preserve detailed DataForSEO error messages * fix: sanitize internal errors and delay domain validation --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../features/audit/launch/LaunchFormCard.tsx | 157 +++--- .../features/audit/launch/LaunchView.tsx | 5 - src/client/features/audit/launch/types.ts | 30 +- .../audit/launch/useLaunchController.ts | 162 +++--- src/client/features/auth/AuthPage.tsx | 20 +- .../backlinks/BacklinksSearchCard.tsx | 468 +++++++++--------- .../features/domain/DomainOverviewPage.tsx | 5 - .../domain/components/DomainSearchCard.tsx | 201 +++----- .../domainOverviewControllerInternals.ts | 94 ++-- .../domain/useDomainOverviewController.ts | 172 +++++-- .../keywords/hooks/useKeywordControlsForm.ts | 65 ++- .../page/KeywordResearchSearchBar.tsx | 53 +- .../state/keywordControllerActions.ts | 142 +----- .../state/keywordControllerInternals.ts | 68 +++ .../state/useKeywordResearchController.ts | 200 ++++---- src/client/lib/error-messages.test.ts | 18 + src/client/lib/error-messages.ts | 1 + src/client/lib/forms.ts | 81 +++ src/routes/_auth.sign-in.tsx | 2 +- src/routes/_auth.sign-up.tsx | 6 +- .../features/domain/services/DomainService.ts | 7 +- src/server/lib/dataforseo.ts | 111 +++-- src/server/lib/domainUtils.ts | 44 ++ src/server/lib/errors.test.ts | 21 + src/server/lib/errors.ts | 3 +- 25 files changed, 1131 insertions(+), 1005 deletions(-) create mode 100644 src/client/features/keywords/state/keywordControllerInternals.ts create mode 100644 src/client/lib/error-messages.test.ts create mode 100644 src/client/lib/forms.ts create mode 100644 src/server/lib/domainUtils.ts create mode 100644 src/server/lib/errors.test.ts diff --git a/src/client/features/audit/launch/LaunchFormCard.tsx b/src/client/features/audit/launch/LaunchFormCard.tsx index 3ac3a65..2e0cea1 100644 --- a/src/client/features/audit/launch/LaunchFormCard.tsx +++ b/src/client/features/audit/launch/LaunchFormCard.tsx @@ -1,29 +1,17 @@ -import type { FormEvent } from "react"; import { Loader2 } from "lucide-react"; import { MAX_PAGES_LIMIT, MIN_PAGES, - type LaunchFormApi, - type LaunchState, } from "@/client/features/audit/launch/types"; +import type { useLaunchController } from "@/client/features/audit/launch/useLaunchController"; +import { getFieldError, getFormError } from "@/client/lib/forms"; -export function LaunchFormCard({ - launchForm, - state, - setState, - isPending, - onSubmit, - onRunLighthouseToggle, - commitMaxPagesInput, -}: { - launchForm: LaunchFormApi; - state: LaunchState; - setState: React.Dispatch>; - isPending: boolean; - onSubmit: (event: FormEvent) => void; - onRunLighthouseToggle: (checked: boolean) => void; +type Props = { + launchForm: ReturnType["launchForm"]; commitMaxPagesInput: () => number; -}) { +}; + +export function LaunchFormCard({ commitMaxPagesInput, launchForm }: Props) { return (
@@ -31,65 +19,68 @@ export function LaunchFormCard({
{ + event.preventDefault(); + void launchForm.handleSubmit(); + }} > - + + {(field) => { + const urlError = getFieldError(field.state.meta.errors); - )} - +
- +
- +
); } -function LaunchOptions({ - launchForm, - commitMaxPagesInput, -}: { - launchForm: LaunchFormApi; - commitMaxPagesInput: () => number; -}) { +function LaunchOptions({ launchForm, commitMaxPagesInput }: Props) { return (