From fbe8dfcc0986026e50647d86c7f79f6efbc95f3c Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sun, 5 Jul 2026 01:14:55 +0000 Subject: [PATCH] Alerts: make hourly free and fix the frequency dropdown - Hourly checks are now available on the free plan (no paywall on frequency); the per-account monthly SERP-call budget remains the cost backstop. Free active-alert cap stays at 50. - The "Check frequency" @@ -166,13 +141,7 @@ export function CreateAlert({ Current results preview (you'll only be emailed NEW ones)

{preview.map((r) => ( - + {r.title || r.url} {r.url} diff --git a/app/(app)/alerts/page.tsx b/app/(app)/alerts/page.tsx index ca4ec2f8..a63a18f5 100644 --- a/app/(app)/alerts/page.tsx +++ b/app/(app)/alerts/page.tsx @@ -27,8 +27,12 @@ type AlertRow = { function fmt(ts: string | null): string { if (!ts) return "not yet"; - const d = new Date(ts); - return d.toLocaleString(undefined, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" }); + return new Date(ts).toLocaleString(undefined, { + month: "short", + day: "numeric", + hour: "numeric", + minute: "2-digit", + }); } export default async function AlertsPage({ @@ -42,10 +46,9 @@ export default async function AlertsPage({ const { data: { user }, } = await supabase.auth.getUser(); - if (!user) redirect("/login"); + if (!user) redirect("/login?next=/alerts"); - // Post-signup: create the alert carried in the magic-link redirect, then - // strip the params so a refresh can't double-create. + // Post-signup magic-link redirect: create the pending alert, then clean the URL. if (newCat && getCategory(newCat)) { await createAlert({ category: newCat, term: term ?? "", customQuery: term ?? "" }); redirect("/alerts"); @@ -84,15 +87,10 @@ export default async function AlertsPage({
{activeCount}/{cap} active {Math.max(0, budget - used)} checks left this month - {plan === "free" && ( - - Upgrade - - )}
- +

diff --git a/lib/alerts/limits.ts b/lib/alerts/limits.ts index 4b63211c..e278f381 100644 --- a/lib/alerts/limits.ts +++ b/lib/alerts/limits.ts @@ -25,9 +25,11 @@ export const SERP_CALLS_PER_MONTH: Record = { team: 1_000_000, }; -// Only paid plans may run hourly; free is daily. -export function allowedFrequencies(plan: Plan): Array<"daily" | "hourly"> { - return plan === "free" ? ["daily"] : ["daily", "hourly"]; +// Hourly is currently free for everyone (no paywall on frequency yet — the +// per-account monthly SERP-call budget is what bounds cost). Revisit if/when +// hourly becomes a paid lever. +export function allowedFrequencies(_plan: Plan): Array<"daily" | "hourly"> { + return ["daily", "hourly"]; } // Results requested per poll and surfaced per email. Capping at 10 keeps SERP