Skip to content

feat(history): implement Phase 1 history improvements with sorting and enhanced search experience#1034

Open
kareena0229 wants to merge 2 commits into
Muneerali199:mainfrom
kareena0229:feature/history-search-sort
Open

feat(history): implement Phase 1 history improvements with sorting and enhanced search experience#1034
kareena0229 wants to merge 2 commits into
Muneerali199:mainfrom
kareena0229:feature/history-search-sort

Conversation

@kareena0229

@kareena0229 kareena0229 commented Jun 26, 2026

Copy link
Copy Markdown

📌 Related Issue

Closes #1032 (Phase 1)

📝 Overview

This PR introduces the first phase of the AI Generation History improvements by enhancing the existing history browsing experience. Instead of implementing the entire feature in one large PR, this contribution focuses on foundational improvements that are easier to review and extend.

✨ What's Included

  • Added sorting options for history items:

    • Newest First
    • Oldest First
    • Alphabetical (A–Z)
  • Integrated sorting with the existing search functionality.

  • Improved the empty state message when no matching documents are found.

  • Preserved existing pagination, tabs, and history navigation behavior.

🚀 Benefits

  • Makes large history lists easier to browse.
  • Improves document discoverability.
  • Creates a foundation for future filtering and favorites functionality.
  • Keeps the history dashboard responsive without affecting existing features.

🧪 Testing

  • ✅ Verified search continues to work.
  • ✅ Verified sorting updates the displayed history items.
  • ✅ Verified empty state appears when no matching documents are found.
  • ✅ Verified existing tabs and pagination continue to function.
  • ✅ Confirmed the feature works in the development environment (npm run dev).

📌 Notes

The production build currently reports unrelated project configuration issues (Supabase environment configuration and existing admin module imports) that are outside the scope of this PR and were not introduced by these changes.

🔮 Future Improvements

This PR intentionally focuses on Phase 1.

Planned follow-up enhancements include:

  • ⭐ Favorites / Bookmarks
  • 🗂 Advanced document-type filters
  • 📅 Additional sorting options
  • 🔖 Dedicated Favorites section

Summary by CodeRabbit

  • New Features
    • Added sort controls for history items (newest, oldest, A–Z) and improved type stats.
    • Updated presentation/resume previews with a slide counter and hover-only progress.
  • Bug Fixes
    • Improved resize handling for previews and reliably resets hover/progress when leaving the preview area.
    • Refreshed empty-state and “no matching documents” messaging.
  • Refactor
    • Reworked history item cards with streamlined view/delete controls and an edit overlay; refreshed preview layouts and styling.

@netlify

netlify Bot commented Jun 26, 2026

Copy link
Copy Markdown

👷 Deploy request for docmagic-muneer pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 5aa0272

@netlify

netlify Bot commented Jun 26, 2026

Copy link
Copy Markdown

👷 Deploy request for docmagic1 pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 5aa0272

@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

@kareena0229 is attempting to deploy a commit to the muneerali199's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The history dashboard now supports URL-synced tabs, sorting, updated history loading, revised preview rendering, and reworked item cards, empty states, pagination, and page-shell presentation.

Changes

History dashboard changes

Layer / File(s) Summary
Metadata and preview setup
components/dashboard/history-dashboard.tsx
Updates preview imports, ContentType, document descriptions, and presentation/resume preview sizing and hover behavior.
Dashboard state and fetch flow
components/dashboard/history-dashboard.tsx
Adds URL-synced tab state, sortBy, Supabase ordering, and concurrent per-type count queries for history loading.
Item routing and preview actions
components/dashboard/history-dashboard.tsx
Updates view routing, nested data access, generated/diagram/letter previews, delete handling, and item-card interactions.
Page shell and list controls
components/dashboard/history-dashboard.tsx
Reworks the page background, stat cards, empty state, pagination, and suspense fallback.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • Muneerali199/Draftdeckai#860: Also updates components/dashboard/history-dashboard.tsx around URL-driven history state, fetch wiring, and pagination behavior.

Suggested reviewers: Muneerali199

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR adds several UI/behavior changes unrelated to search/sort/favorites, like preview hover controls, slide counters, and card layout rewrites. Split the preview/card styling and hover-control changes into a separate PR, keeping this one focused on history search and sorting.
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 (3 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: Phase 1 history improvements focused on sorting and search behavior.
Description check ✅ Passed The PR description covers the issue, overview, changes, testing, and future work, though some template sections are abbreviated.
Linked Issues check ✅ Passed The PR delivers the Phase 1 browsing improvements from #1032: sorting, search integration, empty-state polish, and preserved navigation/performance.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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 `@components/dashboard/history-dashboard.tsx`:
- Around line 327-328: The `activeTab` state in `history-dashboard.tsx` is only
initialized from `urlTab` once, so it can drift from the current `?tab=` value
during browser back/forward navigation. Update the `HistoryDashboard` logic so
`activeTab` stays synchronized with the URL by reacting to `searchParams`
changes (for example in the same area as the `useState(urlTab)` setup and the
fetch/tab logic around the referenced section) and keep the tab setter and
URL-reading code aligned. Ensure the tab used for rendering and data fetching
always reflects the latest `searchParams.get("tab")` value rather than stale
state.
- Around line 122-129: The resume branch in getDocumentDescription is only
checking content.resumeData?.name, which causes many resumes to fall back to
"Resume" and breaks search matching for candidate names. Update the resume case
in getDocumentDescription to also read the display name from
resumeData.personal_info / resumeData.personalInfo (and any existing top-level
name fallback already used elsewhere) before defaulting to "Resume", so the
returned description continues to surface the candidate name for history cards
and filtering.
- Around line 525-528: The switch cases in history-dashboard.tsx are missing
block scope around the "generated" and "letter" branches, so the const
declarations inside them can conflict with other cases. Wrap the bodies of the
switch cases handled by the generated and letter logic in curly braces to create
separate scopes, keeping the declarations local to each case in the switch
statement.
- Around line 126-139: The switch in history-dashboard’s document title logic
has case-level const declarations that violate noSwitchDeclarations. Update the
doc.type switch so the presentation and generated cases use block scopes with
braces around the case bodies, keeping the existing getPresentationSlides and
metadata.sections/doc.sections/content.sections logic intact while isolating the
slides and sections variables.
- Around line 360-423: The sorting in history fetching is applied after
pagination, so the current page is always fetched in newest order and then
reordered locally. Update the query in fetchHistory so the selected sort order
is applied on the Supabase request before range(from, to), using the same sortBy
cases already handled in the local filtered sort logic. Keep the local
setFilteredItems sorting in sync with fetchHistory, but ensure the database
query determines the page contents for newest, oldest, and az.
🪄 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: 657f560d-f3e2-428d-b13e-223b9cc15a35

📥 Commits

Reviewing files that changed from the base of the PR and between c9d7648 and 7e23953.

📒 Files selected for processing (1)
  • components/dashboard/history-dashboard.tsx

Comment thread components/dashboard/history-dashboard.tsx Outdated
Comment thread components/dashboard/history-dashboard.tsx Outdated
Comment thread components/dashboard/history-dashboard.tsx
Comment thread components/dashboard/history-dashboard.tsx Outdated
Comment thread components/dashboard/history-dashboard.tsx
@Muneerali199 Muneerali199 added gssoc:approved Required GSSoC approval label type:feature PR type: feature mentor:muneerali199 Reviewed by mentor muneerali199 labels Jun 26, 2026

@Muneerali199 Muneerali199 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Review: Changes requested

Good work on the sorting and search improvements. I found a few issues that need to be addressed before merging.

Blocking: Pagination + client-side sort gives incorrect results

The sort is applied client-side after pagination. The Supabase query always uses order("created_at", { ascending: false }).range(from, to), so page 1 always contains the newest N items. Then the client re-sorts those N items. This means:

  • "Oldest First" shows the oldest items from the first page of newest results — not the actual globally oldest items
  • "A-Z" sorts only page 1 items alphabetically, missing items on pages 2+

Fix: Apply the sortBy value to the Supabase query before .range(from, to) so pagination reflects the chosen sort order.

Blocking: noSwitchDeclarations — missing block scope in switch cases

Lines 126-139: The case "generated": branch declares const sections without {} block scope. This violates noSwitchDeclarations and will cause a redeclaration error if cases stack.

Fix: Wrap each case body that has const/let declarations in curly braces.

High: activeTab not synced with URL

Line 327: useState(urlTab) only reads the URL on initial mount. Browser back/forward navigation will update the URL but activeTab state will drift.

Fix: Use a useEffect on searchParams.get("tab") to keep activeTab in sync.

Suggestions (non-blocking):

  1. Add level:intermediate label to match the issue complexity
  2. Consider separating formatting-only changes (quotes, import style) from feature changes in future PRs — it inflates the diff

Please address the blocking items and I'll re-review.

@kareena0229

Copy link
Copy Markdown
Author

Review: Changes requested

Good work on the sorting and search improvements. I found a few issues that need to be addressed before merging.

Blocking: Pagination + client-side sort gives incorrect results

The sort is applied client-side after pagination. The Supabase query always uses order("created_at", { ascending: false }).range(from, to), so page 1 always contains the newest N items. Then the client re-sorts those N items. This means:

  • "Oldest First" shows the oldest items from the first page of newest results — not the actual globally oldest items
  • "A-Z" sorts only page 1 items alphabetically, missing items on pages 2+

Fix: Apply the sortBy value to the Supabase query before .range(from, to) so pagination reflects the chosen sort order.

Blocking: noSwitchDeclarations — missing block scope in switch cases

Lines 126-139: The case "generated": branch declares const sections without {} block scope. This violates noSwitchDeclarations and will cause a redeclaration error if cases stack.

Fix: Wrap each case body that has const/let declarations in curly braces.

High: activeTab not synced with URL

Line 327: useState(urlTab) only reads the URL on initial mount. Browser back/forward navigation will update the URL but activeTab state will drift.

Fix: Use a useEffect on searchParams.get("tab") to keep activeTab in sync.

Suggestions (non-blocking):

  1. Add level:intermediate label to match the issue complexity
  2. Consider separating formatting-only changes (quotes, import style) from feature changes in future PRs — it inflates the diff

Please address the blocking items and I'll re-review.

Will update Soon

@kareena0229

Copy link
Copy Markdown
Author

Thanks for the detailed review! It has been helpful to me.

I've addressed the requested changes:

  • ✅ Applied sorting at the Supabase query level before pagination, so sorting now works correctly across all pages.
  • ✅ Wrapped switch cases containing const declarations in block scope to satisfy noSwitchDeclarations.
  • ✅ Synced activeTab with the URL using useEffect, so browser back/forward navigation correctly updates the selected tab.

I also verified the changes locally, and all project tests passed successfully (394 tests).

Please let me know if there are any additional improvements you'd like me to make. Thanks again for the helpful feedback! @Muneerali199

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
components/dashboard/history-dashboard.tsx (2)

444-461: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid positional index mapping of typeCounts.

typeCounts[0..4] assumes Object.keys(contentTypeConfig) enumerates exactly in the order resume, presentation, generated, diagram, letter. If the config keys are ever reordered or a type is added/removed, the counts silently map to the wrong stat. Build the result by associating each count with its source key instead.

♻️ Map counts by type key
-        const typeCounts = await Promise.all(
-          Object.keys(contentTypeConfig).map((type) =>
-            supabase
-              .from("documents")
-              .select("id", { count: "exact", head: true })
-              .eq("user_id", user.id)
-              .eq("type", type),
-          ),
-        );
-
-        setStats({
-          total: count || 0,
-          resume: typeCounts[0].count || 0,
-          presentation: typeCounts[1].count || 0,
-          generated: typeCounts[2].count || 0,
-          diagram: typeCounts[3].count || 0,
-          letter: typeCounts[4].count || 0,
-        });
+        const types = Object.keys(contentTypeConfig) as ContentType[];
+        const typeCounts = await Promise.all(
+          types.map((type) =>
+            supabase
+              .from("documents")
+              .select("id", { count: "exact", head: true })
+              .eq("user_id", user.id)
+              .eq("type", type),
+          ),
+        );
+        const countsByType = Object.fromEntries(
+          types.map((type, i) => [type, typeCounts[i].count || 0]),
+        ) as Record<ContentType, number>;
+
+        setStats({
+          total: count || 0,
+          resume: countsByType.resume || 0,
+          presentation: countsByType.presentation || 0,
+          generated: countsByType.generated || 0,
+          diagram: countsByType.diagram || 0,
+          letter: countsByType.letter || 0,
+        });
🤖 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 `@components/dashboard/history-dashboard.tsx` around lines 444 - 461, The stats
aggregation in history-dashboard.tsx is relying on positional access to
typeCounts, which can break if contentTypeConfig key order changes. Update the
Promise.all mapping around the count query to preserve each type key with its
result, then build setStats from a keyed lookup rather than typeCounts[0..4].
Use the existing type names from contentTypeConfig and the stats fields in
setStats to ensure each document count is assigned to the correct category.

800-810: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

sortBy is not URL-backed unlike tab/page/pageSize.

Tab and pagination are persisted via updateQueryParams, but the sort selection lives only in local state. Browser back/forward and refresh won't restore it, which is slightly inconsistent with the URL-backed history-navigation contract. Also consider resetting page to 1 when the sort changes so users aren't left on an out-of-range page. Optional for Phase 1.

🤖 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 `@components/dashboard/history-dashboard.tsx` around lines 800 - 810, The sort
selection in history-dashboard’s select control is only stored in local state,
unlike tab/page/pageSize which are synced through updateQueryParams. Update the
sortBy change handler in HistoryDashboard to write the new sort value into the
URL query params (using the same pattern as the existing pagination/tab
setters), and also reset page to 1 when the sort changes so navigation stays
consistent and avoids out-of-range pages. Use the existing sortBy state and
updateQueryParams helper to locate and wire this behavior.
🤖 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.

Nitpick comments:
In `@components/dashboard/history-dashboard.tsx`:
- Around line 444-461: The stats aggregation in history-dashboard.tsx is relying
on positional access to typeCounts, which can break if contentTypeConfig key
order changes. Update the Promise.all mapping around the count query to preserve
each type key with its result, then build setStats from a keyed lookup rather
than typeCounts[0..4]. Use the existing type names from contentTypeConfig and
the stats fields in setStats to ensure each document count is assigned to the
correct category.
- Around line 800-810: The sort selection in history-dashboard’s select control
is only stored in local state, unlike tab/page/pageSize which are synced through
updateQueryParams. Update the sortBy change handler in HistoryDashboard to write
the new sort value into the URL query params (using the same pattern as the
existing pagination/tab setters), and also reset page to 1 when the sort changes
so navigation stays consistent and avoids out-of-range pages. Use the existing
sortBy state and updateQueryParams helper to locate and wire this behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f6fcc0eb-57f4-4614-b87d-114093700b76

📥 Commits

Reviewing files that changed from the base of the PR and between 7e23953 and f768d90.

📒 Files selected for processing (1)
  • components/dashboard/history-dashboard.tsx

@Muneerali199

Copy link
Copy Markdown
Owner

@kareena0229 main has advanced with recent merges — please rebase and I'll re-approve. The review is approved pending rebase.

@kareena0229
kareena0229 force-pushed the feature/history-search-sort branch from f768d90 to 5aa0272 Compare July 3, 2026 15:57
@kareena0229

Copy link
Copy Markdown
Author

Hi @Muneerali199

Thanks for the update!

I've rebased my branch onto the latest main and force-pushed the updated branch.

I also reran the project's test suite after rebasing, and all tests passed successfully.

Please let me know if there's anything else you'd like me to address. Thanks again for your review!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
components/dashboard/history-dashboard.tsx (1)

444-461: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Map per-type counts by type name, not array position.

setStats assumes typeCounts[0..4] correspond to resume/presentation/generated/diagram/letter, which only holds while Object.keys(contentTypeConfig) stays in that exact order. Reordering or adding a key to contentTypeConfig would silently misassign the stat cards. Keying the results by type removes the positional coupling.

Suggested refactor
-        const typeCounts = await Promise.all(
-          Object.keys(contentTypeConfig).map((type) =>
-            supabase
-              .from("documents")
-              .select("id", { count: "exact", head: true })
-              .eq("user_id", user.id)
-              .eq("type", type),
-          ),
-        );
-
-        setStats({
-          total: count || 0,
-          resume: typeCounts[0].count || 0,
-          presentation: typeCounts[1].count || 0,
-          generated: typeCounts[2].count || 0,
-          diagram: typeCounts[3].count || 0,
-          letter: typeCounts[4].count || 0,
-        });
+        const types = Object.keys(contentTypeConfig);
+        const typeCounts = await Promise.all(
+          types.map((type) =>
+            supabase
+              .from("documents")
+              .select("id", { count: "exact", head: true })
+              .eq("user_id", user.id)
+              .eq("type", type),
+          ),
+        );
+
+        const countsByType = Object.fromEntries(
+          types.map((type, i) => [type, typeCounts[i].count || 0]),
+        );
+        setStats({
+          total: count || 0,
+          resume: countsByType.resume || 0,
+          presentation: countsByType.presentation || 0,
+          generated: countsByType.generated || 0,
+          diagram: countsByType.diagram || 0,
+          letter: countsByType.letter || 0,
+        });
🤖 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 `@components/dashboard/history-dashboard.tsx` around lines 444 - 461, The
per-type document counts in history-dashboard are still mapped by array index,
which couples setStats to the order of Object.keys(contentTypeConfig). Update
the Promise.all result handling in history-dashboard.tsx to associate each count
with its type name from contentTypeConfig, then build setStats from those keyed
values instead of typeCounts[0..4]. Use the existing contentTypeConfig keys and
the setStats call to locate the refactor.
🤖 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.

Nitpick comments:
In `@components/dashboard/history-dashboard.tsx`:
- Around line 444-461: The per-type document counts in history-dashboard are
still mapped by array index, which couples setStats to the order of
Object.keys(contentTypeConfig). Update the Promise.all result handling in
history-dashboard.tsx to associate each count with its type name from
contentTypeConfig, then build setStats from those keyed values instead of
typeCounts[0..4]. Use the existing contentTypeConfig keys and the setStats call
to locate the refactor.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3c58d5db-7cae-4bf4-90df-37a4c7dfaedc

📥 Commits

Reviewing files that changed from the base of the PR and between f768d90 and 5aa0272.

📒 Files selected for processing (1)
  • components/dashboard/history-dashboard.tsx

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

Labels

gssoc:approved Required GSSoC approval label level:intermediate GSSoC difficulty: intermediate mentor:muneerali199 Reviewed by mentor muneerali199 type:feature PR type: feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add Advanced Search, Filter & Favorites System for AI Generation History

2 participants