Skip to main content

Feed

Location: src/components/Feed.jsx

Overview

Feed is the central content display for CommonPlace. Unlike conventional social feeds, it enforces slow-feed pacing to prevent addictive scrolling patterns. Posts are divided into new (since the user last visit) and previous (before the last visit) groups, giving users a clear sense of completion rather than an endless stream.

The component supports three pacing modes (slow, normal, live) and a filter system that includes base filters (all posts, friends only) plus dynamic per-circle filters. Real-time subscriptions are only active in live mode.

Relevant Invariants

  • Invariant #2: "Calm Is the Default State" -- Feed defaults to normal mode (1-hour refresh), with no urgency cues or auto-loading.
  • Invariant #8: "Feed Is a View, Not a Goal" -- Posts are session-bounded, not ranked or scored.
  • Invariant #12: "Slowness Is Baked In" -- Batched loading with explicit refresh and paced intervals.
  • Invariant #13: "Absence Is First-Class" -- Empty feeds display a calm completion state, not a broken one.

Props

PropTypeRequiredDefaultDescription
sessionobjectYes--Supabase auth session with user.id
feedModestringYes--Current pacing mode: slow, normal, or live
setFeedModefunctionYes--Callback to change the pacing mode
showComposerbooleanYes--Whether the inline CreatePost form is visible
onCloseComposerfunctionYes--Callback when user closes the inline composer

Constants

ConstantValueDescription
PACING_INTERVALS.slow21600000 (6 hrs)Minimum time between feed refreshes in slow mode
PACING_INTERVALS.normal3600000 (1 hr)Minimum time between feed refreshes in normal mode
PACING_INTERVALS.live0No restriction; real-time subscription active
PREVIOUS_POSTS_PAGE_SIZE20Number of previous posts loaded per page

Key Behaviors

  • Session Cutoff: Uses user_feed_state.last_checked_at to divide posts into new vs. previous groups.
  • Pacing Gate: In slow/normal modes, the feed only re-fetches if enough time has elapsed since last_checked_at.
  • Filter Persistence: The selected filter is stored in localStorage under the key feedFilter.
  • Circle Filters: Dynamically generated from the user circles via useCircles hook, appearing alongside base filters.
  • Real-time: Only in live mode, a Supabase channel subscription pushes new posts into the feed.
  • Stepped-back Friends: Uses useSteppedBack to apply visual indicators for friends in a stepped-back state.

Usage

import Feed from '@/components/Feed';

function App({ session }) {
const [feedMode, setFeedMode] = useState('normal');
const [showComposer, setShowComposer] = useState(false);

return (
<Feed
session={session}
feedMode={feedMode}
setFeedMode={setFeedMode}
showComposer={showComposer}
onCloseComposer={() => setShowComposer(false)}
/>
);
}
  • Post -- Individual post rendering
  • CreatePost -- Inline post creation form
  • Header -- Feed mode selector lives here

Last updated: 2026-02-07