feat: add 'recently viewed' repos section to discovery page#872
Conversation
- Implements a 'Recently Viewed' horizontal scroll section that persists across page loads using localStorage Fixes Sachinchaurasiya360#701
|
Hi @ThePrabhu, thanks for contributing to InternHack! 🎉 I have automatically:
Our workflows will now analyze your changes to classify:
Tip Ensure your PR description references the issue it resolves (e.g. Happy coding! 🚀 |
|
Caution Review failedFailed to post review comments 📝 WalkthroughWalkthroughAdds a recently viewed repos feature: a localStorage-backed hook, a horizontally scrollable UI strip, and RepoDiscoveryPage wiring that records selections, deep-links the open repo via the ChangesRecently Viewed Repositories
Sequence DiagramsequenceDiagram
participant User
participant RepoCard
participant RepoDiscoveryPage
participant Hook as useRecentlyViewedRepos:addRepo
participant Storage as localStorage
participant Modal as Detail Modal
User->>RepoCard: click repo
RepoCard->>RepoDiscoveryPage: onSelect(repo)
RepoDiscoveryPage->>RepoDiscoveryPage: handleOpenRepo(repo)
RepoDiscoveryPage->>Hook: addRepo(repo)
Hook->>Storage: persist updated list
Storage-->>Hook: write complete
RepoDiscoveryPage->>RepoDiscoveryPage: set repo URL param
RepoDiscoveryPage->>Modal: setSelectedRepo(repo)
Modal-->>User: show detail
RepoDiscoveryPage-->>User: RecentlyViewedSection updated
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly Related PRs
Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds “recently viewed repositories” to the student open source repo discovery experience, persisting selections in localStorage and rendering a new UI section.
Changes:
- Introduces a
useRecentlyViewedReposhook that loads/saves recently viewed repos tolocalStorage. - Adds a
RecentlyViewedSectioncomponent to display the stored repos. - Wires repo selection in
RepoDiscoveryPageto record views (partially).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| client/src/module/student/opensource/useRecentlyViewedRepos.ts | New hook for reading/writing recently viewed repos in localStorage. |
| client/src/module/student/opensource/_shared/RecentlyViewedSection.tsx | New UI component to render the “Recently Viewed” horizontal list. |
| client/src/module/student/opensource/RepoDiscoveryPage.tsx | Integrates the hook + section into the discovery page and updates selection handling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| {/* Recently Viewed */} | ||
| <RecentlyViewedSection repos={recentlyViewed} onSelect={setSelectedRepo} /> |
| const addRepo = useCallback((repo: OpenSourceRepo) => { | ||
| setRecentlyViewed((prev) => { | ||
| const newRecentlyViewed = [repo, ...prev.filter((r) => r.id !== repo.id)].slice(0, MAX_RECENTLY_VIEWED); | ||
| try { | ||
| localStorage.setItem(STORAGE_KEY, JSON.stringify(newRecentlyViewed)); | ||
| } catch (error) { | ||
| console.error("Failed to save recently viewed repos to localStorage", error); | ||
| } | ||
| return newRecentlyViewed; | ||
| }); | ||
| }, []); |
| @@ -0,0 +1,44 @@ | |||
| import { ChevronRight } from "lucide-react"; | |||
|
@Sachinchaurasiya360 , Review the code |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
client/src/module/student/opensource/_shared/RecentlyViewedSection.tsx (2)
40-40: ⚡ Quick winUse
bg-linear-to-linstead ofbg-gradient-to-l.Coding guidelines require the v4
bg-linear-*form over thebg-gradient-*shorthand.As per coding guidelines: "Use `bg-linear-to-*` instead of `bg-gradient-*` shorthand in TailwindCSS".♻️ Proposed fix
- <div className="absolute right-0 top-0 bottom-2 w-8 bg-gradient-to-l from-stone-50 dark:from-stone-950 to-transparent pointer-events-none" /> + <div className="absolute right-0 top-0 bottom-2 w-8 bg-linear-to-l from-stone-50 dark:from-stone-950 to-transparent pointer-events-none" />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@client/src/module/student/opensource/_shared/RecentlyViewedSection.tsx` at line 40, In RecentlyViewedSection replace the Tailwind gradient utility on the overflow-fade div by using the v4 form: change the className token "bg-gradient-to-l" to "bg-linear-to-l" so the element (the div with classes "absolute right-0 top-0 bottom-2 w-8 ... pointer-events-none") uses the v4 bg-linear-* utility; ensure no other classes are altered and run the build to verify Tailwind picks up the updated utility.
1-1: ⚡ Quick winRemove unused
ChevronRightimport.It's imported but never used in the JSX, which will fail the build under
noUnusedLocals/lint.♻️ Proposed fix
-import { ChevronRight } from "lucide-react"; import type { OpenSourceRepo } from "../../../lib/types";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@client/src/module/student/opensource/_shared/RecentlyViewedSection.tsx` at line 1, Remove the unused import ChevronRight from RecentlyViewedSection.tsx: locate the import statement importing ChevronRight and delete it (or replace it with any actually used icon import) so the module no longer contains an unused local; ensure no other references to ChevronRight remain in the file (e.g., JSX or helpers) before committing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@client/src/module/student/opensource/_shared/RecentlyViewedSection.tsx`:
- Line 29: In RecentlyViewedSection.tsx update the Tailwind class on the element
that currently uses "flex-shrink-0" (the className string on the container in
the RecentlyViewedSection component) to the canonical v4 utility "shrink-0" so
it works with Tailwind v4; simply replace "flex-shrink-0" with "shrink-0" in
that className.
In `@client/src/module/student/opensource/RepoDiscoveryPage.tsx`:
- Line 241: The RecentlyViewedSection is wired to call setSelectedRepo directly,
which opens the modal but bypasses addRepo and therefore doesn't update recency;
change the prop to use the existing handler handleSelectRepo (the same function
used by the repo cards) so selection funnels through addRepo and reorders the
recentlyViewed list—locate the RecentlyViewedSection usage and replace
onSelect={setSelectedRepo} with onSelect={handleSelectRepo}, ensuring
handleSelectRepo remains responsible for calling addRepo and setting selected
repo.
In `@client/src/module/student/opensource/useRecentlyViewedRepos.ts`:
- Around line 12-15: The code reads STORAGE_KEY from localStorage and calls
setRecentlyViewed(JSON.parse(stored)) without verifying the parsed value is an
array, which can cause RecentlyViewedSection to crash if storage contains
null/object/number; update the initialization in useRecentlyViewedRepos so after
parsing you assert Array.isArray(parsed) (and optionally that items match
expected repo-shape) before calling setRecentlyViewed, otherwise ignore the
value or set an empty array and remove or overwrite the bad STORAGE_KEY; refer
to the STORAGE_KEY constant, the setRecentlyViewed setter, and the
RecentlyViewedSection consumer when making this change.
---
Nitpick comments:
In `@client/src/module/student/opensource/_shared/RecentlyViewedSection.tsx`:
- Line 40: In RecentlyViewedSection replace the Tailwind gradient utility on the
overflow-fade div by using the v4 form: change the className token
"bg-gradient-to-l" to "bg-linear-to-l" so the element (the div with classes
"absolute right-0 top-0 bottom-2 w-8 ... pointer-events-none") uses the v4
bg-linear-* utility; ensure no other classes are altered and run the build to
verify Tailwind picks up the updated utility.
- Line 1: Remove the unused import ChevronRight from RecentlyViewedSection.tsx:
locate the import statement importing ChevronRight and delete it (or replace it
with any actually used icon import) so the module no longer contains an unused
local; ensure no other references to ChevronRight remain in the file (e.g., JSX
or helpers) before committing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e034a216-c8b5-45d3-9659-a2b214966a4c
📒 Files selected for processing (3)
client/src/module/student/opensource/RepoDiscoveryPage.tsxclient/src/module/student/opensource/_shared/RecentlyViewedSection.tsxclient/src/module/student/opensource/useRecentlyViewedRepos.ts
| key={repo.id} | ||
| type="button" | ||
| onClick={() => onSelect(repo)} | ||
| className="flex-shrink-0 w-48 text-left p-3 rounded-md bg-white dark:bg-stone-900 border border-stone-200 dark:border-white/10 hover:border-stone-400 dark:hover:border-white/25 transition-colors" |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Tailwind CSS v4, is flex-shrink-0 deprecated in favor of shrink-0?
💡 Result:
Yes, in Tailwind CSS v4, the class flex-shrink-0 has been removed and is deprecated in favor of shrink-0 [1]. As part of the cleanup for the v4 major release, Tailwind CSS removed several utility aliases that had been deprecated for some time [1]. Specifically, the flex-shrink-* family of utilities was replaced by the shorter, canonical shrink-* naming convention [2][1]. To update your project, it is recommended to use the official Tailwind CSS upgrade tool, which automatically handles the renaming of these legacy classes [2][1][3]: npx @tailwindcss/upgrade This tool will scan your codebase and replace instances of flex-shrink-0 with shrink-0, along with other similar renames (such as flex-grow-* to grow-*) [4][2][1].
Citations:
- 1: https://tailwindcss.com/docs/upgrade-guide
- 2: https://www.digitalapplied.com/blog/tailwind-css-v4-migration-new-features-guide
- 3: https://designrevision.com/blog/tailwind-4-migration
- 4: Migrate legacy classes to the v4 alternative tailwindlabs/tailwindcss#14643
Replace flex-shrink-0 with canonical shrink-0 (Tailwind v4)
Tailwind v4 removed the flex-shrink-* aliases; use shrink-0 instead.
♻️ Proposed fix
- className="flex-shrink-0 w-48 text-left p-3 rounded-md bg-white dark:bg-stone-900 border border-stone-200 dark:border-white/10 hover:border-stone-400 dark:hover:border-white/25 transition-colors"
+ className="shrink-0 w-48 text-left p-3 rounded-md bg-white dark:bg-stone-900 border border-stone-200 dark:border-white/10 hover:border-stone-400 dark:hover:border-white/25 transition-colors"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| className="flex-shrink-0 w-48 text-left p-3 rounded-md bg-white dark:bg-stone-900 border border-stone-200 dark:border-white/10 hover:border-stone-400 dark:hover:border-white/25 transition-colors" | |
| className="shrink-0 w-48 text-left p-3 rounded-md bg-white dark:bg-stone-900 border border-stone-200 dark:border-white/10 hover:border-stone-400 dark:hover:border-white/25 transition-colors" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@client/src/module/student/opensource/_shared/RecentlyViewedSection.tsx` at
line 29, In RecentlyViewedSection.tsx update the Tailwind class on the element
that currently uses "flex-shrink-0" (the className string on the container in
the RecentlyViewedSection component) to the canonical v4 utility "shrink-0" so
it works with Tailwind v4; simply replace "flex-shrink-0" with "shrink-0" in
that className.
| const stored = localStorage.getItem(STORAGE_KEY); | ||
| if (stored) { | ||
| setRecentlyViewed(JSON.parse(stored)); | ||
| } |
There was a problem hiding this comment.
Validate that parsed storage value is an array.
JSON.parse succeeds for valid-but-wrong-shape JSON (e.g. "null", "{}", "5"), so a corrupted oss_recently_viewed entry would set recentlyViewed to a non-array. RecentlyViewedSection then runs repos.length === 0 / repos.map(...) on a non-array and throws at render. The try/catch only guards parse syntax errors.
🛡️ Proposed guard
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
- setRecentlyViewed(JSON.parse(stored));
+ const parsed = JSON.parse(stored);
+ if (Array.isArray(parsed)) {
+ setRecentlyViewed(parsed);
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const stored = localStorage.getItem(STORAGE_KEY); | |
| if (stored) { | |
| setRecentlyViewed(JSON.parse(stored)); | |
| } | |
| const stored = localStorage.getItem(STORAGE_KEY); | |
| if (stored) { | |
| const parsed = JSON.parse(stored); | |
| if (Array.isArray(parsed)) { | |
| setRecentlyViewed(parsed); | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@client/src/module/student/opensource/useRecentlyViewedRepos.ts` around lines
12 - 15, The code reads STORAGE_KEY from localStorage and calls
setRecentlyViewed(JSON.parse(stored)) without verifying the parsed value is an
array, which can cause RecentlyViewedSection to crash if storage contains
null/object/number; update the initialization in useRecentlyViewedRepos so after
parsing you assert Array.isArray(parsed) (and optionally that items match
expected repo-shape) before calling setRecentlyViewed, otherwise ignore the
value or set an empty array and remove or overwrite the bad STORAGE_KEY; refer
to the STORAGE_KEY constant, the setRecentlyViewed setter, and the
RecentlyViewedSection consumer when making this change.
Sachinchaurasiya360
left a comment
There was a problem hiding this comment.
Clean implementation. The useRecentlyViewedRepos hook correctly deduplicates, caps at 5, and handles localStorage errors gracefully. The RecentlyViewedSection has a proper early-return guard and integrates well with the existing deep-link and recommendation sections.
One item to verify: RecentlyViewedSection.tsx lives in _shared/ and imports type { OpenSourceRepo } from '../../../lib/types'. From that subdirectory, three ../ steps only reach client/src/module/ — the correct path should be ../../../../lib/types. If TypeScript resolves this via a path alias, that is fine; otherwise please correct the import path.
Approving and merging.
ebb2a3b
into
Sachinchaurasiya360:main
Description
This PR introduces a Recently Viewed Repositories feature that helps users quickly access repositories they have recently explored.
The feature automatically tracks repositories opened from the discovery page, stores them in localStorage, and displays them in a dedicated horizontal scroll section. The list persists across page reloads, prevents duplicate entries, and maintains a maximum history of five repositories.
This enhancement improves repository discovery and provides a more personalized browsing experience.
Related Issue
Fixes #701
Type of Change
Testing
Manual Testing Performed
Screenshots
UI screenshots demonstrating the Recently Viewed section and persistence behavior can be attached here.
Checklist
.env, credentials, ornode_modulescommittedSummary by CodeRabbit