diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a896b4f..f4b276a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: NODE_OPTIONS: --max-old-space-size=4096 - name: Lint - run: npx next lint + run: npm run lint # `next lint` was removed in Next.js 16 # Confirms full-migration.sql still matches the real database. Separate job # because it needs credentials, and it should not block a PR from a fork. diff --git a/eslint.config.mjs b/eslint.config.mjs index 05e726d..1a41e40 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -5,6 +5,11 @@ import nextTs from "eslint-config-next/typescript"; const eslintConfig = defineConfig([ ...nextVitals, ...nextTs, + { + // 238 pre-existing `any`s predate enforced linting in CI; surface them as + // warnings and tighten back to "error" as they are typed. + rules: { "@typescript-eslint/no-explicit-any": "warn" }, + }, // Override default ignores of eslint-config-next. globalIgnores([ // Default ignores of eslint-config-next: diff --git a/src/app/(dashboard)/outreach/page.tsx b/src/app/(dashboard)/outreach/page.tsx index 6ed82e4..67bfad1 100644 --- a/src/app/(dashboard)/outreach/page.tsx +++ b/src/app/(dashboard)/outreach/page.tsx @@ -26,6 +26,8 @@ export default function OutreachPage() { }, []); useEffect(() => { + // Initial data load; fetchCampaigns sets loading state before awaiting. + // eslint-disable-next-line react-hooks/set-state-in-effect fetchCampaigns(); }, [fetchCampaigns]); diff --git a/src/app/(dashboard)/settings/integrations/page.tsx b/src/app/(dashboard)/settings/integrations/page.tsx index 8d8fdf8..20b79e7 100644 --- a/src/app/(dashboard)/settings/integrations/page.tsx +++ b/src/app/(dashboard)/settings/integrations/page.tsx @@ -41,7 +41,7 @@ export default function IntegrationsPage() { const res = await fetch("/api/calendar/connect"); const data = await res.json(); if (data.url) { - window.location.href = data.url; + window.location.assign(data.url); } } catch { setConnecting(null); diff --git a/src/app/api/ai/chat/route.ts b/src/app/api/ai/chat/route.ts index bafd292..e47db10 100644 --- a/src/app/api/ai/chat/route.ts +++ b/src/app/api/ai/chat/route.ts @@ -37,7 +37,7 @@ export async function POST(request: NextRequest) { ); // Agentic loop with tool use - let currentMessages = [...conversationMessages]; + const currentMessages = [...conversationMessages]; let finalResponse = ""; let iterations = 0; const maxIterations = 5; diff --git a/src/app/pricing/page.tsx b/src/app/pricing/page.tsx index a3cbdda..9d424ec 100644 --- a/src/app/pricing/page.tsx +++ b/src/app/pricing/page.tsx @@ -48,11 +48,11 @@ function getFeatures(planId: "free" | "pro" | "enterprise"): string[] { export default function PricingPage() { async function handleSubscribe(planId: "free" | "pro" | "enterprise") { if (planId === "free") { - window.location.href = "/auth/signup"; + window.location.assign("/auth/signup"); return; } if (planId === "enterprise") { - window.location.href = "mailto:sales@aismartr.com"; + window.location.assign("mailto:sales@aismartr.com"); return; } // For pro, redirect to checkout @@ -63,7 +63,7 @@ export default function PricingPage() { body: JSON.stringify({ price_id: priceId }), }); const { url } = await res.json(); - if (url) window.location.href = url; + if (url) window.location.assign(url); } return ( diff --git a/src/components/advisory/deal-selector.tsx b/src/components/advisory/deal-selector.tsx index 54fb81c..c805308 100644 --- a/src/components/advisory/deal-selector.tsx +++ b/src/components/advisory/deal-selector.tsx @@ -27,7 +27,9 @@ export function DealSelector({ onSelect, onClear, selectedDealId }: DealSelector }, []); useEffect(() => { + // Keep local selection in sync with the controlled selectedDealId prop. if (!selectedDealId) { + // eslint-disable-next-line react-hooks/set-state-in-effect setSelectedDeal(null); } else { const deal = deals.find((d) => d.id === selectedDealId); diff --git a/src/lib/analytics.ts b/src/lib/analytics.ts index daf0423..aa900a5 100644 --- a/src/lib/analytics.ts +++ b/src/lib/analytics.ts @@ -8,7 +8,7 @@ type AnalyticsEvent = | { event: "deal_created"; properties: { source?: string } } | { event: "company_imported"; properties: { count: number; source: string } } | { event: "campaign_launched"; properties: { channel_count: number; contact_count: number } } - | { event: "icp_configured"; properties: {} } + | { event: "icp_configured"; properties: Record } | { event: "integration_connected"; properties: { provider: string } } | { event: "plan_upgraded"; properties: { from: string; to: string } };