- {/* Attach menu — photo / video / document / voice. Beta-gated:
- hidden entirely for accounts not opted into 'chat_media'. */}
- {chatMediaEnabled && (
-
-
- {busy ? (
-
- ) : (
-
- )}
-
-
- imageInputRef.current?.click()}>
-
- Photo
-
- videoInputRef.current?.click()}>
-
- Video
-
- documentInputRef.current?.click()}>
-
- Document
-
- void startRecording()}>
-
- Voice note
-
-
-
- )}
+ {/* Attach menu — photo / video / document / voice. */}
+
+
+ {busy ? (
+
+ ) : (
+
+ )}
+
+
+ imageInputRef.current?.click()}>
+
+ Photo
+
+ videoInputRef.current?.click()}>
+
+ Video
+
+ documentInputRef.current?.click()}>
+
+ Document
+
+ void startRecording()}>
+
+ Voice note
+
+
+
+
Type '/' for quick replies
)}
diff --git a/src/hooks/use-beta-feature.ts b/src/hooks/use-beta-feature.ts
deleted file mode 100644
index bb128ea..0000000
--- a/src/hooks/use-beta-feature.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-"use client";
-
-import { useAuth } from "@/hooks/use-auth";
-import { hasBetaFeature, type BetaFeature } from "@/lib/auth/beta-features";
-
-/**
- * Boolean gate for a per-profile beta feature flag (see
- * `@/lib/auth/beta-features`). Mirrors `useCan`: returns `false` while the
- * profile is still loading so a not-yet-opted-in user never sees a flash
- * of beta UI during the initial load window.
- *
- * Example:
- * const chatMedia = useBetaFeature(CHAT_MEDIA_BETA);
- * {chatMedia && }
- */
-export function useBetaFeature(feature: BetaFeature): boolean {
- const { profileLoading, profile } = useAuth();
- if (profileLoading || !profile) return false;
- return hasBetaFeature(profile.beta_features, feature);
-}
diff --git a/src/lib/auth/beta-features.test.ts b/src/lib/auth/beta-features.test.ts
deleted file mode 100644
index b8a374a..0000000
--- a/src/lib/auth/beta-features.test.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { describe, expect, it } from "vitest";
-import { CHAT_MEDIA_BETA, hasBetaFeature } from "./beta-features";
-
-describe("hasBetaFeature", () => {
- it("is true when the feature key is present", () => {
- expect(hasBetaFeature([CHAT_MEDIA_BETA], CHAT_MEDIA_BETA)).toBe(true);
- expect(hasBetaFeature(["flows", CHAT_MEDIA_BETA], CHAT_MEDIA_BETA)).toBe(true);
- });
-
- it("is false when the key is absent", () => {
- expect(hasBetaFeature(["flows"], CHAT_MEDIA_BETA)).toBe(false);
- expect(hasBetaFeature([], CHAT_MEDIA_BETA)).toBe(false);
- });
-
- it("is false (not throwing) for null / undefined lists", () => {
- expect(hasBetaFeature(null, CHAT_MEDIA_BETA)).toBe(false);
- expect(hasBetaFeature(undefined, CHAT_MEDIA_BETA)).toBe(false);
- });
-});
diff --git a/src/lib/auth/beta-features.ts b/src/lib/auth/beta-features.ts
deleted file mode 100644
index 7da0f58..0000000
--- a/src/lib/auth/beta-features.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Beta feature flags, stored per-profile in `profiles.beta_features`
- * (a `TEXT[]`, migration 011). A feature is "on" for an account when its
- * key is present in that array; the owner opts in by editing the column
- * in Supabase Studio:
- *
- * UPDATE profiles
- * SET beta_features = array_append(beta_features, 'chat_media')
- * WHERE email = 'someone@example.com';
- *
- * This module is the single source of truth for the keys + the membership
- * check so the client hook (`useBetaFeature`) and the server routes gate
- * on exactly the same logic.
- */
-
-/** Agent-initiated media sends in the inbox composer (issue #213). */
-export const CHAT_MEDIA_BETA = "chat_media";
-
-export type BetaFeature = typeof CHAT_MEDIA_BETA;
-
-/**
- * Whether an opted-in feature list contains `feature`. Pure + null-safe so
- * both the client (reading `profile.beta_features`) and the server
- * (reading the row from Supabase) share one implementation.
- */
-export function hasBetaFeature(
- betaFeatures: readonly string[] | null | undefined,
- feature: BetaFeature,
-): boolean {
- return betaFeatures?.includes(feature) ?? false;
-}