Merged
Conversation
…te endpoints (closes #55) - Add activity logging side-effect documentation to POST /videos/id/{video_id}/view, POST /videos/{video_id}/comments, and POST /videos/{video_id}/ratings - Add videoid field to UserActivityResponse schema (required alongside userid, activity_type, activity_id, activity_timestamp) - Add enum constraint on activity_type: view | comment | rate - Add PaginatedResponse_UserActivityResponse_ schema and /users/{id}/activity endpoint to complete the spec for the activity timeline feature Backend implementation note: the backend must write a user_activity row on each authenticated view, each comment post, and each rating upsert (new or updated). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents POST /api/v1/videos/id/{video_id_path}/watch-time with 204/400/401
responses and the VideoWatchTimeRequest schema (watch_duration_seconds integer,
minimum 1). Append-only semantics and JWT auth requirement are described in the
operation description.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#57) Adds `recordWatchTime(videoId, durationSeconds)` to the API client and a `useRecordWatchTime()` React Query mutation hook following the existing `recordView` pattern. Also adds `RecordWatchTimeRequest` to the domain types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Accumulates elapsed seconds while the Watch page is visible, reporting to the API as a heartbeat every 30 s, on tab-hide (visibilitychange), and on page unload. Unload uses fetch with keepalive + auth header so the request survives tab/window close. Zero-second flushes are skipped. All intervals and listeners are cleaned up on unmount. Existing view tracking (useRecordView) is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#59) - Add getUserActivity() method to ApiClient with activity_type, page, and pageSize filtering - Add useUserActivity() React Query hook with CACHE_STRATEGY.SHORT stale time, disabled when userId is undefined - Define UserActivity and UserActivityResponse types in src/types/api.ts matching the OpenAPI schema Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new ActivityTimeline component that displays a paginated, filterable feed of user activity (views, comments, ratings) on the Profile page. Supports filtering by activity type via tabs and pagination following the Explore page pattern. Uses native Intl-compatible relative time formatting (no date-fns needed). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eview endpoint (refs #61, #62, #63) - Fix #61: rename page_size → pageSize in getLatestVideos query string (closes #61) - Fix #62: remove non-existent /watch-time endpoint — delete recordWatchTime() from ApiClient, useRecordWatchTime hook from useApi.ts, all watch-time tracking logic from Watch.tsx, and /watch-time path from OpenAPI spec (closes #62) - Fix #63: implement previewYoutubeVideo() on ApiClient (POST /videos/preview) and usePreviewVideo() mutation hook; add VideoPreviewResponse type (closes #63) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Errors fixed (6): - CommentsSection, ExplainerModal, WelcomeModal, useTooltipContent, Creator: add eslint-disable-next-line for react-hooks/set-state-in-effect where setState inside useEffect is correct (async query data, loading flags, localStorage side effects) - sidebar.tsx: replace useMemo(Math.random) with useState lazy initializer to satisfy react-hooks/purity rule Warnings fixed (7): - eslint.config.js: add src/components/ui/** override to disable react-refresh/only-export-components for shadcn-generated files (badge, button, sonner, toggle, sidebar) - eslint.config.js: add .claude to ignores to exclude worktree dirs - useAuth.tsx: add eslint-disable-next-line for useAuth hook export - useApi.ts: move uuidRegex to module scope to fix exhaustive-deps warning Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR covers two areas of technical debt cleanup:
API Compliance (closes #61, #62, #63)
A full audit of frontend API calls against the backend OpenAPI spec revealed three issues:
getLatestVideossentpage_size(snake_case) instead ofpageSize(camelCase), causing silent 422 errors on all Home page paginationrecordWatchTimecalledPOST /videos/id/{id}/watch-time, an endpoint that doesn't exist on the live backend (returns 404 on every heartbeat). Removed the method, hook, all watch-time tracking logic from the Watch page, and the path from the OpenAPI spec. View count is correctly tracked via the existinguseRecordViewcall.previewYoutubeVideo()API method andusePreviewVideo()mutation hook forPOST /api/v1/videos/preview, which returns the YouTube video title for pre-filling the submit formESLint Cleanup
Resolved all 13 pre-existing lint issues (6 errors, 7 warnings) that had accumulated in the codebase:
react-hooks/set-state-in-effecterrors in CommentsSection, ExplainerModal, WelcomeModal, useTooltipContent, Creator — all legitimatesetStatepatterns in effects responding to async data; suppressed with inline disable commentsreact-hooks/purityerror insidebar.tsx— replaceduseMemo(Math.random)withuseStatelazy initializerreact-refresh/only-export-componentswarnings in shadcn/ui files — suppressed via ESLint config override forsrc/components/ui/**(avoids editing generated files)react-hooks/exhaustive-depswarning inuseApi.ts— moveduuidRegexto module scopereact-refresh/only-export-componentswarning inuseAuth.tsx— inline disable comment onuseAuthhook exportnpm run lintnow exits with 0 problems.npm run buildclean.Test plan
/watch-timenpm run lint→ 0 problemsnpm run build→ clean🤖 Generated with Claude Code