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({
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