From 1c4d3a6bd77d04e3587d0131eaec29aded662244 Mon Sep 17 00:00:00 2001 From: Bilal Godil Date: Tue, 26 May 2026 15:48:17 -0700 Subject: [PATCH] feat(dashboard): skip rebrand modal in dev/preview environments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds an explicit short-circuit at the top of HexclaveRebrandModal that returns no modal when any of the three NEXT_PUBLIC_STACK_IS_* dev flags is true — local emulator, remote development environment, or preview. These surfaces either auto-create throwaway users (preview) or seed a fixture admin (emulator/RDE). The rebrand notice would be friction for developers logging into local dev and meaningless for preview visitors who never used "Stack Auth" in the first place. Coincidentally these users are also filtered out today by signedUpAt < REBRAND_CUTOFF (fresh preview signups happen after the cutoff; a freshly-seeded emulator admin also signs up post-cutoff), but the explicit env-flag guard is more defensive — it stays correct if the cutoff is ever bumped forward for a test. Same three flags the protected layout already gates on (apps/dashboard/src/app/(main)/(protected)/layout-client.tsx:15-17). --- .../src/components/hexclave-rebrand-modal.tsx | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/dashboard/src/components/hexclave-rebrand-modal.tsx b/apps/dashboard/src/components/hexclave-rebrand-modal.tsx index c57000228..260517465 100644 --- a/apps/dashboard/src/components/hexclave-rebrand-modal.tsx +++ b/apps/dashboard/src/components/hexclave-rebrand-modal.tsx @@ -9,6 +9,7 @@ import { DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; +import { getPublicEnvVar } from "@/lib/env"; import { useUser } from "@stackframe/stack"; import Image from "next/image"; import { useEffect, useState } from "react"; @@ -25,16 +26,30 @@ const REBRAND_CUTOFF = new Date("2026-05-27T00:00:00.000Z"); /** * One-time informational modal announcing the Stack Auth → Hexclave rebrand. * - * Only renders for a logged-in user who signed up before {@link REBRAND_CUTOFF}. - * On any dismissal (confirm button, close button, overlay click, or Escape) - * writes `STORAGE_KEY` to localStorage so the modal never re-appears for that - * browser. + * Skipped entirely in preview / local-emulator / remote-development environments + * — those auto-create throwaway users or seed a fixture admin, so the rebrand + * notice would be friction for developers and meaningless for preview visitors + * who never used "Stack Auth" in the first place. + * + * For real customers: only renders for a logged-in user who signed up before + * {@link REBRAND_CUTOFF}. On any dismissal (confirm button, close button, + * overlay click, or Escape) writes `STORAGE_KEY` to localStorage so the modal + * never re-appears for that browser. */ export function HexclaveRebrandModal() { + // Skip in dev/preview environments — same flags the protected layout already + // gates on. Read at top so we can short-circuit before any hook runs the + // useEffect or computes the user-based gate. + const isDevEnvironment = + getPublicEnvVar("NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR") === "true" + || getPublicEnvVar("NEXT_PUBLIC_STACK_IS_REMOTE_DEVELOPMENT_ENVIRONMENT") === "true" + || getPublicEnvVar("NEXT_PUBLIC_STACK_IS_PREVIEW") === "true"; + // `or: "return-null"` keeps this from triggering the sign-in redirect when // it's rendered above the auth boundary — we simply opt out for guests. const user = useUser({ or: "return-null" }); - const isPreRebrandUser = user != null && user.signedUpAt < REBRAND_CUTOFF; + const isPreRebrandUser = + !isDevEnvironment && user != null && user.signedUpAt < REBRAND_CUTOFF; const [open, setOpen] = useState(false); // Read localStorage after hydration to avoid SSR mismatch — render closed