Skip to content

feat(subscriptions): inbox page + nav link#128

Open
aloewright wants to merge 2 commits into
mainfrom
feat/subscriptions-page
Open

feat(subscriptions): inbox page + nav link#128
aloewright wants to merge 2 commits into
mainfrom
feat/subscriptions-page

Conversation

@aloewright
Copy link
Copy Markdown
Owner

@aloewright aloewright commented May 15, 2026

Summary

  • New /subscriptions route (RequireAuth-gated) renders a grid of new videos from channels the signed-in user follows.
  • On mount: fetches GET /api/users/me/inbox?limit=50, then fires POST /api/users/me/inbox/seen to clear the unseen counter for the next visit.
  • Header nav (signed-in only) gains a "Subscriptions" button next to Upload/Profile.
  • Empty state nudges back to trending; error state surfaces the failure.
  • Analytics: track('subscriptions_inbox_viewed', { count }) on successful load.

The subscriptions Worker (src/workers/subscriptions.ts) and all its endpoints already shipped with full integration coverage (15 tests via #124), but had no frontend surface. This is the missing piece that closes the ALO-124 "subscribed viewer is notified when a creator they follow uploads" acceptance.

Bundle impact: new Subscriptions-*.js chunk at 2.97 kB raw / 1.40 kB gz; no regression to other route chunks.

Test plan

  • npm run lint — clean (no errors)
  • npm run type-check — clean
  • npm test -- --run — 48 files, 509 tests pass (+3 vs main)
  • npm run build — clean
  • Three DOM tests on Subscriptions.tsx cover happy path, empty state, fetch error

Refs ALO-124

https://claude.ai/code/session_01KYVQhoiq656KTnYLnphKpJ


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added authenticated Subscriptions page enabling users to view and manage inbox items from followed channels with thumbnails, channel links, and relative timestamps.
  • Tests

    • Added comprehensive test suite for Subscriptions page covering item display, empty states, and error handling.

Review Change Stack

New `/subscriptions` route (RequireAuth-gated) shows a grid of new videos
from channels the signed-in user follows. On mount it fetches
`GET /api/users/me/inbox?limit=50` and fires `POST /api/users/me/inbox/seen`
to clear the unseen counter for the next visit. Empty state nudges the
viewer back to trending. The signed-in header nav gains a "Subscriptions"
button.

The subscriptions Worker (`src/workers/subscriptions.ts`) and all its
endpoints already shipped with full integration coverage (15 tests via
PR #124) but had no frontend surface; this is the missing piece that
closes the ALO-124 "subscribed viewer is notified when a creator they
follow uploads" acceptance.

Bundle: new `Subscriptions-*.js` chunk at 2.97 kB raw / 1.40 kB gz; no
regression to other route chunks.

Refs ALO-124

https://claude.ai/code/session_01KYVQhoiq656KTnYLnphKpJ
Copilot AI review requested due to automatic review settings May 15, 2026 13:20
@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 15, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

Warning

Rate limit exceeded

@aloewright has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 56 minutes and 10 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 272a567d-2665-4bc7-b3ba-ed16c2394aa6

📥 Commits

Reviewing files that changed from the base of the PR and between 27843bc and 6857467.

📒 Files selected for processing (1)
  • src/frontend/pages/Subscriptions.tsx

Walkthrough

This PR adds a new auth-protected Subscriptions inbox page to the frontend. It includes route registration with lazy loading, a React component that fetches and displays user inbox items with relative timestamps, and a comprehensive test suite covering success, empty, and error states.

Changes

Subscriptions Inbox Page Feature

Layer / File(s) Summary
Route registration and navigation
src/frontend/App.tsx
Introduces a lazy-loaded code split for the Subscriptions component, registers a /subscriptions route protected by RequireAuth, and adds a "Subscriptions" button to the signed-in header navigation.
Subscriptions page implementation
src/frontend/pages/Subscriptions.tsx
Defines the page component with inbox item types, a relative-time timeSince utility, a mount effect that fetches items (with analytics tracking) and marks them as seen, conditional rendering for error/loading/empty/populated states, and an InboxCard sub-component displaying video thumbnails, channel links, and timestamps.
Test suite
src/frontend/pages/Subscriptions.dom.test.tsx
Provides test setup with DOM utilities and async helpers, sample test data, mocked fetch hooks, and three test cases validating successful item rendering with correct links and seen-item POST, empty inbox display, and fetch error handling.

Sequence Diagram

sequenceDiagram
  participant SubscriptionsComponent
  participant FetchAPI
  participant InboxAPI as /api/users/me/inbox
  participant SeenAPI as /api/users/me/inbox/seen
  participant Analytics
  SubscriptionsComponent->>FetchAPI: Fetch inbox items on mount
  FetchAPI->>InboxAPI: GET with credentials and query params
  InboxAPI-->>FetchAPI: Return items array or empty
  FetchAPI-->>SubscriptionsComponent: Store items in state
  SubscriptionsComponent->>Analytics: Track event with item count
  SubscriptionsComponent->>SeenAPI: POST to mark items seen (fire-and-forget)
  SubscriptionsComponent->>SubscriptionsComponent: Render error/loading/empty/InboxCard grid
Loading

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(subscriptions): inbox page + nav link' accurately and concisely summarizes the main changes: adding a subscriptions inbox page with a navigation link.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/subscriptions-page

Warning

Review ran into problems

🔥 Problems

These MCP integrations need to be re-authenticated in the Integrations settings: Sentry


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new Subscriptions feature, adding a dedicated page, routing, and a navigation link in the header. The Subscriptions page fetches a user's inbox items, displays them in a grid of cards, and includes logic to mark the inbox as seen. Comprehensive DOM tests are also included. Feedback focuses on improving the reliability of date parsing for cross-browser compatibility, ensuring consistent credential handling in API requests to match the rest of the application, and adding a CSS class for visual consistency during page transitions.

Comment thread src/frontend/pages/Subscriptions.tsx Outdated
Comment on lines +28 to +29
const t = Date.parse(iso);
if (Number.isNaN(t)) return '';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The Date.parse call may fail or return incorrect results in some browsers (like Safari) because SQLite's CURRENT_TIMESTAMP format (YYYY-MM-DD HH:MM:SS) is not a strictly valid ISO 8601 string. This can lead to the date being interpreted as local time or failing to parse entirely (returning NaN). Normalizing the string by adding the 'T' separator and 'Z' suffix ensures reliable cross-browser parsing as UTC.

Suggested change
const t = Date.parse(iso);
if (Number.isNaN(t)) return '';
const normalized = iso.includes('T') ? iso : iso.replace(' ', 'T') + 'Z';
const t = Date.parse(normalized);
if (Number.isNaN(t)) return '';

Comment thread src/frontend/pages/Subscriptions.tsx Outdated

useEffect(() => {
let cancelled = false;
void fetch(`/api/users/me/inbox?limit=${PAGE_LIMIT}`, { credentials: 'include' })
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of credentials: 'include' is inconsistent with other API calls in the application (e.g., in App.tsx), which use credentials: 'same-origin'. Since the API is on the same origin, same-origin is preferred to avoid unnecessarily sending credentials on potential cross-origin requests.

Suggested change
void fetch(`/api/users/me/inbox?limit=${PAGE_LIMIT}`, { credentials: 'include' })
void fetch(`/api/users/me/inbox?limit=${PAGE_LIMIT}`, { credentials: 'same-origin' })

Comment thread src/frontend/pages/Subscriptions.tsx Outdated
// this call is non-fatal — the inbox itself loaded fine.
void fetch('/api/users/me/inbox/seen', {
method: 'POST',
credentials: 'include',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consistency: Use credentials: 'same-origin' to match the rest of the application's API requests.

Suggested change
credentials: 'include',
credentials: 'same-origin',

Comment thread src/frontend/pages/Subscriptions.tsx Outdated
}, []);

return (
<main className="app-main stack">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To maintain visual consistency with the Home page and other main routes, consider adding the fade-in class to the main container.

Suggested change
<main className="app-main stack">
<main className="app-main stack fade-in">

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Three gemini-code-assist review findings on PR #128:

* `timeSince` was calling `Date.parse` on `added_at` straight from D1.
  SQLite's `CURRENT_TIMESTAMP` is `YYYY-MM-DD HH:MM:SS` (no T, no Z),
  which Safari's parser can refuse or interpret as local time. Normalize
  to ISO-8601 UTC before parsing so the relative-time string is correct
  cross-browser.
* `credentials: 'include'` → `'same-origin'` on both `/inbox` GET and
  `/inbox/seen` POST to match the rest of the app (Watch, Comments,
  ReportButton, auth-client, sessions all use same-origin; only the
  legacy AccountSettings page still uses include).
* Add `fade-in` to the root `<main>` and switch `stack` → `stack-lg` so
  the page matches the visual rhythm of every other discovery surface
  (Channel, Watch, Search, Tag, Pricing).

https://claude.ai/code/session_01KYVQhoiq656KTnYLnphKpJ
@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 15, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 27843bc646

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/frontend/pages/Subscriptions.tsx Outdated
const PAGE_LIMIT = 50;

function timeSince(iso: string): string {
const t = Date.parse(iso);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize inbox timestamps as UTC before relative-time math

subscription_inbox.added_at is stored as SQLite CURRENT_TIMESTAMP (UTC without an explicit offset) and returned by /api/users/me/inbox unchanged, so feeding it directly into Date.parse(iso) makes browsers interpret it as local time; for non-UTC users this can skew relative times by hours (including showing recent uploads as just now for too long). Please normalize to an explicit UTC/W3C timestamp before computing timeSince.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants