From 5ec24d9542de8921a7d40e385e5cd46e654d8f2a Mon Sep 17 00:00:00 2001 From: talksik Date: Tue, 7 Apr 2026 14:42:06 -0700 Subject: [PATCH] cleanup message retention code --- js/src/api/client.ts | 9 --- js/src/api/types.ts | 2 +- js/src/features/network-settings.tsx | 62 ------------------- .../features/particles/particle-list-view.tsx | 10 --- js/src/features/particles/stream-card.tsx | 11 +--- js/src/hooks/use-expiring-soon.ts | 20 ------ js/src/hooks/use-network-settings.ts | 13 ---- js/src/hooks/use-stream-playback.ts | 20 +++--- 8 files changed, 9 insertions(+), 138 deletions(-) delete mode 100644 js/src/hooks/use-expiring-soon.ts delete mode 100644 js/src/hooks/use-network-settings.ts diff --git a/js/src/api/client.ts b/js/src/api/client.ts index bac9f8f..378dfbf 100644 --- a/js/src/api/client.ts +++ b/js/src/api/client.ts @@ -178,15 +178,6 @@ class ApiClient { ); } - async setMessageRetentionHours(networkId: string, hours: number) { - return this.request( - NetworkSchema, - "PUT", - `/networks/${networkId}/message-retention`, - { hours }, - ); - } - // --- Invitations --- async listNetworkInvitations(networkId: string) { diff --git a/js/src/api/types.ts b/js/src/api/types.ts index 3e7ef23..0619974 100644 --- a/js/src/api/types.ts +++ b/js/src/api/types.ts @@ -14,7 +14,6 @@ export const NetworkSchema = z.object({ name: z.string(), admin_human: HumanSchema, humans: z.array(HumanSchema), - message_retention_hours: z.number(), created_at: z.coerce.date(), }); @@ -186,6 +185,7 @@ export const ParticleSchema = z.discriminatedUnion("type", [ last_child_created_at: z.coerce.date().optional(), // Array of humanIds currently in the huddle (updated via LiveKit webhooks) huddle_active_participants: z.array(z.string()).optional(), + status: z.enum(["open", "closed"]).optional(), }), ParticleBaseSchema.extend({ type: z.literal("folder"), properties: FolderPropertiesSchema, diff --git a/js/src/features/network-settings.tsx b/js/src/features/network-settings.tsx index 0368fb8..b2ca79d 100644 --- a/js/src/features/network-settings.tsx +++ b/js/src/features/network-settings.tsx @@ -8,11 +8,9 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; -import { Slider } from "@/components/ui/slider"; import { Muted } from "@/components/ui/typography"; import { WindowControls } from "@/components/window-controls"; import { useNetworks } from "@/hooks/use-networks"; -import { useSetMessageRetention } from "@/hooks/use-network-settings"; import { useNetworkInvitations, useInviteMembers, @@ -150,54 +148,6 @@ function SettingsGroup({ ); } -function formatRetentionDays(hours: number): string { - const days = Math.round(hours / 24); - return days === 1 ? "1 day" : `${days} days`; -} - -function EphemeralitySettings({ networkId, retentionHours }: { networkId: string; retentionHours: number }) { - const setRetention = useSetMessageRetention(networkId); - const [days, setDays] = useState(Math.round(retentionHours / 24)); - const debounceRef = useRef>(undefined); - - // Sync local state if server value changes externally - useEffect(() => { - setDays(Math.round(retentionHours / 24)); - }, [retentionHours]); - - const handleChange = useCallback((value: number[]) => { - const newDays = value[0]; - setDays(newDays); - - if (debounceRef.current) clearTimeout(debounceRef.current); - debounceRef.current = setTimeout(() => { - setRetention.mutate(newDays * 24, { - onSuccess: () => toast.success("Retention window updated"), - onError: (err) => toast.error(err.message || "Failed to update retention"), - }); - }, 500); - }, [setRetention]); - - return ( -
-
-

Messages disappear after

-

{formatRetentionDays(days * 24)}

-
- - - Older messages are no longer visible to anyone. - -
- ); -} - export default function NetworkSettingsPage() { const navigate = useNavigate(); const { networkId } = useParams<{ networkId: string }>(); @@ -240,18 +190,6 @@ export default function NetworkSettingsPage() { ))} - {isAdmin && network && ( - <> - - - - - - )} - {isAdmin && network && ( diff --git a/js/src/features/particles/particle-list-view.tsx b/js/src/features/particles/particle-list-view.tsx index dd8df4a..cb49c18 100644 --- a/js/src/features/particles/particle-list-view.tsx +++ b/js/src/features/particles/particle-list-view.tsx @@ -9,7 +9,6 @@ import { FileText, CircleCheck, StickyNote, - Timer, Headphones, type LucideIcon, } from "lucide-react"; @@ -28,7 +27,6 @@ import { Progress } from "@/components/ui/progress"; import { Small } from "@/components/ui/typography"; import type { Particle, StreamProperties } from "@/api/types"; import { useNetwork } from "@/hooks/use-networks"; -import { useExpiringSoon } from "@/hooks/use-expiring-soon"; import { useStreamParticles } from "@/hooks/use-stream-particles"; import { useStreamAutoplay } from "@/hooks/use-stream-autoplay"; @@ -97,11 +95,6 @@ function StreamRow({ useStreamAutoplay(latestChild, particle, networkId, network ?? undefined); - const expiringSoon = useExpiringSoon( - particle.last_child_created_at, - network?.message_retention_hours ?? 24, - ); - const hasActiveHuddle = particle.huddle_active_participants && particle.huddle_active_participants.length > 0; const huddleCount = particle.huddle_active_participants?.length ?? 0; @@ -201,9 +194,6 @@ function StreamRow({ {huddleCount} )} - {expiringSoon && ( - - )} {latestChild && ( (function S useStreamAutoplay(latestChild, particle, networkId, network ?? undefined); - const expiringSoon = useExpiringSoon( - particle.last_child_created_at, - network?.message_retention_hours ?? 24, - ); - const hasActiveHuddle = particle.huddle_active_participants && particle.huddle_active_participants.length > 0; const huddleCount = particle.huddle_active_participants?.length ?? 0; @@ -155,9 +149,6 @@ export const StreamCard = forwardRef(function S {huddleCount} )} - {expiringSoon && ( - - )} {latestChild && ( { - if (!lastChildCreatedAt) return false; - - const retentionMs = retentionHours * 60 * 60 * 1000; - const expiresAt = lastChildCreatedAt.getTime() + retentionMs; - const remaining = expiresAt - Date.now(); - - return remaining > 0 && remaining < retentionMs * 0.1; - }, [lastChildCreatedAt, retentionHours]); -} diff --git a/js/src/hooks/use-network-settings.ts b/js/src/hooks/use-network-settings.ts deleted file mode 100644 index 002c936..0000000 --- a/js/src/hooks/use-network-settings.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { apiClient } from "@/api/client"; - -export function useSetMessageRetention(networkId: string) { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (hours: number) => - apiClient.setMessageRetentionHours(networkId, hours), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["networks"] }); - }, - }); -} diff --git a/js/src/hooks/use-stream-playback.ts b/js/src/hooks/use-stream-playback.ts index 6abd9f6..5e0f7f6 100644 --- a/js/src/hooks/use-stream-playback.ts +++ b/js/src/hooks/use-stream-playback.ts @@ -4,8 +4,6 @@ import type { Particle } from "@/api/types"; import { useLiveParticleChildren } from "@/hooks/use-particle"; import { parseParticlePath, toFirestoreDocPath, type ParticlePath } from "@/lib/particle-path"; import { updateStreamPlaybackMarker } from "@/lib/firestore-particles"; -import { where, Timestamp } from "firebase/firestore"; -import { useNetwork } from "@/hooks/use-networks"; // --- Playback reducer (ID-based) --- @@ -96,9 +94,6 @@ export function useStreamPlayback( path: ParticlePath, ): UseStreamPlaybackResult { const userId = useAuthStore((s) => s.user?.id); - const { networkId } = parseParticlePath(path); - const network = useNetwork(networkId); - const retentionHours = network?.message_retention_hours ?? 24; const [state, dispatch] = useReducer(playbackReducer, initialState); // Track the stream ID we've initialized for, to reset when navigating between streams const initializedForRef = useRef(null); @@ -118,15 +113,14 @@ export function useStreamPlayback( }); }); - const [recencyCutoff] = useState(() => { - const d = new Date(); - d.setHours(d.getHours() - retentionHours); - return Timestamp.fromDate(d); - }); - const { children } = useLiveParticleChildren( - path, "created_at", "asc", undefined, onParticleAdded, onParticleRemoved, - where("created_at", ">=", recencyCutoff), + path, + { + orderByField: "created_at", + orderDirection: "asc", + onAdded: onParticleAdded, + onRemoved: onParticleRemoved + } ); // Derive current index and particle from ID