Skip to content

feat: sidebar#39

Merged
BIA3IA merged 52 commits into
mainfrom
sidebar
Jun 11, 2026
Merged

feat: sidebar#39
BIA3IA merged 52 commits into
mainfrom
sidebar

Conversation

@lorenzocorallo

Copy link
Copy Markdown
Member

No description provided.

@lorenzocorallo lorenzocorallo requested a review from BIA3IA June 5, 2026 20:13
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@BIA3IA, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 54 minutes and 57 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 772bac77-7d1c-425e-bcf6-e2b2ec01ca4b

📥 Commits

Reviewing files that changed from the base of the PR and between 4797e44 and 6e1be95.

📒 Files selected for processing (17)
  • src/app/dashboard/(active)/account/page.tsx
  • src/app/dashboard/(active)/azure/members/table.tsx
  • src/app/dashboard/(active)/not-found.tsx
  • src/app/dashboard/(active)/telegram/grants/grant-list.tsx
  • src/app/dashboard/(active)/telegram/grants/loading.tsx
  • src/app/dashboard/(active)/telegram/grants/page.tsx
  • src/app/dashboard/(active)/telegram/groups/group-row.tsx
  • src/app/dashboard/(active)/telegram/groups/loading.tsx
  • src/app/dashboard/(active)/telegram/groups/page.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/card-audit-log.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/loading.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/page.tsx
  • src/app/dashboard/(active)/telegram/users/loading.tsx
  • src/app/dashboard/(active)/telegram/users/page.tsx
  • src/components/search-input.tsx
  • src/index.css
  • src/server/actions/users.ts

Walkthrough

This PR introduces a sidebar navigation system with cookie-backed state persistence, breadcrumb routing from the current route, and updates the dashboard shell layout. Legacy header navigation is removed, pages are standardized to simpler container layouts, callback-based component interactions are refactored to use router.refresh(), and a new Telegram user details page with aggregated user data is added.

Changes

Dashboard Sidebar Navigation Migration

Layer / File(s) Summary
Cookie utilities and client-side storage hooks
src/constants.ts, src/utils/cookies.ts, src/hooks/use-cookie-storage.tsx, src/hooks/use-session-storage.tsx
Defines COOKIES constant with sidebar state keys, implements setCookie/getCookie/deleteCookie utilities with SSR guards and environment-aware defaults, and adds useCookieStorage and useSessionStorage hooks for reactive state hydration and client-side persistence.
Sidebar provider, context, and UI component library
src/components/ui/sidebar.tsx, src/index.css, src/components/ui/alert.tsx, src/components/ui/button.tsx
Implements SidebarProvider with cookie-backed open state, keyboard toggle shortcut (Cmd/Ctrl+B), responsive mobile Sheet mode and desktop layout; exports composable sidebar building blocks (Trigger, Rail, structural wrappers, group/menu/submenu components) with CVA-based styling and slot metadata; adds dark theme sidebar color tokens and container utility.
Dashboard sidebar data, main navigation, and user navigation
src/components/dashboard-sidebar/data.tsx, src/components/dashboard-sidebar/main-nav.tsx, src/components/dashboard-sidebar/index.tsx, src/components/dashboard-sidebar/user-nav.tsx
Defines DSData Telegram/Azure navigation structure and builds NAV_MAP title lookup; implements DSMainNav with cookie-backed category collapse state and automatic URL prefix matching; renders user avatar/name/email dropdown with logout action and account link; wires navigation to dashboard sidebar layout.
Breadcrumb navigation and active dashboard layout
src/app/dashboard/(active)/breadcrumb.tsx, src/app/dashboard/(active)/layout.tsx
Derives breadcrumbs from pathname and NAV_MAP, falls back to heuristic title-casing/Details for ID segments; integrates SidebarProvider, DashboardSidebar, SidebarTrigger, and Breadcrumb into the active layout with cookie-driven category state and sidebar width CSS variable.
Legacy header removal and dashboard structure updates
src/app/dashboard/layout.tsx, src/app/layout.tsx, src/app/dashboard/(active)/page.tsx
Removes AdminHeader component from dashboard layout, removes horizontal padding from root layout, updates AdminHome page to remove async session fetch and navigation cards, replaces with "Page under construction" alert.
Page container spacing standardization
src/app/dashboard/(active)/azure/page.tsx, src/app/dashboard/(active)/azure/members/page.tsx, src/app/dashboard/(active)/telegram/grants/page.tsx, src/app/dashboard/(active)/telegram/groups/page.tsx, src/app/dashboard/(active)/telegram/user-details/page.tsx, src/app/dashboard/(active)/telegram/grants/loading.tsx, src/app/dashboard/(active)/azure/members/loading.tsx, src/app/dashboard/(active)/telegram/groups/loading.tsx, src/app/dashboard/(active)/telegram/users/loading.tsx
Removes p-8 padding from page containers and standardizes to container class only; updates corresponding loading skeleton layouts to match; updates Azure page flex/gap styling; cleans up unused icon imports.
Callback removal and router.refresh refactoring
src/app/dashboard/(active)/complete-profile.tsx, src/app/dashboard/(active)/telegram/grants/delete-grant.tsx, src/app/dashboard/(active)/telegram/users/[id]/add-role.tsx, src/app/dashboard/(active)/telegram/users/[id]/card-*.tsx, src/app/dashboard/(active)/telegram/users/[id]/delete-group-admin.tsx, src/app/dashboard/(active)/telegram/users/[id]/new-group-admin.tsx, src/app/dashboard/(active)/telegram/users/[id]/remove-role.tsx
Refactors components to remove callback props (onDelete, onAdd, onConfirm, onUpdate) and instead call router.refresh() on successful operations; updates CompleteProfile to fetch session via useSession() hook instead of server-side prop; affects parent-child component prop contracts throughout the Telegram user management flow.
New Telegram user details page with aggregated data
src/app/dashboard/(active)/telegram/users/[id]/page.tsx, src/app/dashboard/(active)/telegram/users/[id]/loading.tsx, src/server/actions/users.ts, src/app/dashboard/(active)/telegram/users/page.tsx
Adds async TgUserDetails page that fetches aggregated user data (roles, group admin status, recent messages, audit logs, grants) via new getUserDetails action; renders multiple card sections with Suspense-wrapped audit logs and empty-state messages; updates users list to 4-column grid with actions link to user details; adds loading skeleton page; replaces searchUser with getUserDetails in server actions; removes TelegramIndex page.
Loading skeletons and minor UI refinements
src/app/dashboard/(active)/account/loading.tsx, src/app/dashboard/(active)/account/page.tsx
Adds account page loading skeleton with user field and passkeys placeholders; updates avatar styling by removing rounded-lg classes to flatten appearance.

Possibly Related PRs

  • PoliNetworkOrg/admin#22: Updates the DeleteGrant component API to remove the onDelete callback in favor of router.refresh() pattern, directly parallel to callback refactoring in this PR.
  • PoliNetworkOrg/admin#17: Modifies account page avatar and fallback styling (Avatar/AvatarFallback classes) in the same file where this PR removes rounded-lg classes.
🚥 Pre-merge checks | ✅ 3 | ❌ 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 (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: sidebar' is directly related to the main changes in the PR, which add comprehensive sidebar functionality including new components, navigation structures, and cookie-based state management.
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.


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.

@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 `@src/app/dashboard/`(active)/layout.tsx:
- Around line 9-12: The layout reads a client-controlled cookie into cookie and
directly JSON.parse's it into DSCategoryState which can throw on malformed
input; wrap the parse in a safe guard (try/catch) or use a safeJsonParse helper
around the cookie value and fall back to an empty object on error so
layout.tsx’s DSCategoryState is always an object and parsing failures are
logged/ignored; update the code that references cookieStore, cookie and
DSCategoryState to use this safe parse.

In `@src/app/dashboard/`(active)/telegram/groups/page.tsx:
- Line 26: The column header text "Hide" in the groups listing is misleading
because the last column in GroupRow (component/group-row.tsx,
functions/rendering around the hide toggle and leave-chat actions) contains both
the hide toggle and leave-chat controls; update the header in page.tsx (where
the <p>Hide</p> is defined) to a more accurate label such as "Actions" or
"Controls" (or "Hide / Leave" if you prefer explicitness) and adjust any
associated aria-labels/tooltip text to match so the header aligns with the
actual controls rendered by GroupRow.

In `@src/components/dashboard-sidebar/data.tsx`:
- Around line 27-37: flattenNavigation currently only maps first-level items
from DSData so nested route titles are missing in NAV_MAP; update
flattenNavigation (and its inner traverse) to recursively walk child arrays
(e.g., items with a children or items property) and add every node with a url to
the map, ensuring NAV_MAP contains entries for nested routes used by
breadcrumb.tsx; locate flattenNavigation, DSData, traverse, and NAV_MAP and make
traverse call itself for child lists and/or child properties until all nested
nodes are added.

In `@src/components/dashboard-sidebar/main-nav.tsx`:
- Around line 21-27: DSMenuCategory currently creates its own
useCookieStorage(COOKIES.SIDEBAR_CATEGORY_STATE) per instance which causes
concurrent writes to clobber each other and also mutates state in place;
instead, move the single useCookieStorage(COOKIES.SIDEBAR_CATEGORY_STATE) call
up into DSMainNav (call it once to get shared categoryState and
setCategoryState) and pass the state and setter down to DSMenuCategory as props;
ensure DSMenuCategory updates use an immutable setter (no in-place mutation of
the state object—use a new object like {...state, [title]: newValue}) so toggles
for one category won’t overwrite others.
- Around line 77-79: The nav highlighting uses exact equality (const path =
usePathname(); const isActive = path === item.url) so nested/detail routes don't
mark the parent active; change the logic in the component that computes isActive
(where usePathname(), path and item.url are referenced) to treat the item as
active when the current path startsWith the item.url (and normalize trailing
slashes or handle the root "/" case) so parent menu items remain highlighted for
nested routes.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 11cd920e-0253-4982-bc61-5efb30ca7cd4

📥 Commits

Reviewing files that changed from the base of the PR and between 1181e18 and 454e9db.

📒 Files selected for processing (30)
  • src/app/dashboard/(active)/account/page.tsx
  • src/app/dashboard/(active)/azure/members/page.tsx
  • src/app/dashboard/(active)/azure/page.tsx
  • src/app/dashboard/(active)/breadcrumb.tsx
  • src/app/dashboard/(active)/layout.tsx
  • src/app/dashboard/(active)/page.tsx
  • src/app/dashboard/(active)/telegram/grants/page.tsx
  • src/app/dashboard/(active)/telegram/groups/group-row.tsx
  • src/app/dashboard/(active)/telegram/groups/page.tsx
  • src/app/dashboard/(active)/telegram/page.tsx
  • src/app/dashboard/(active)/telegram/user-details/page.tsx
  • src/app/dashboard/(active)/telegram/user-details/remove-role.tsx
  • src/app/dashboard/(active)/telegram/user-list/page.tsx
  • src/app/dashboard/layout.tsx
  • src/app/layout.tsx
  • src/app/page.tsx
  • src/components/admin-header/index.tsx
  • src/components/admin-header/right-nav.tsx
  • src/components/dashboard-sidebar/data.tsx
  • src/components/dashboard-sidebar/index.tsx
  • src/components/dashboard-sidebar/main-nav.tsx
  • src/components/dashboard-sidebar/user-nav.tsx
  • src/components/ui/sidebar.tsx
  • src/constants.ts
  • src/hooks/use-cookie-storage.tsx
  • src/hooks/use-session-storage.tsx
  • src/index.css
  • src/lib/i18n.ts
  • src/utils/cookies.ts
  • tsconfig.json
💤 Files with no reviewable changes (4)
  • src/lib/i18n.ts
  • src/components/admin-header/index.tsx
  • src/app/dashboard/(active)/telegram/page.tsx
  • src/components/admin-header/right-nav.tsx

Comment thread src/app/dashboard/(active)/layout.tsx Outdated
Comment thread src/app/dashboard/(active)/telegram/groups/page.tsx Outdated
Comment thread src/components/dashboard-sidebar/data.tsx
Comment thread src/components/dashboard-sidebar/main-nav.tsx
Comment thread src/components/dashboard-sidebar/main-nav.tsx
@lorenzocorallo lorenzocorallo marked this pull request as draft June 5, 2026 21:06
@lorenzocorallo

Copy link
Copy Markdown
Member Author

ci sono dei bug nella persistence degli stati open dei collapsible che devo fixare

@lorenzocorallo lorenzocorallo marked this pull request as ready for review June 5, 2026 21:16

@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: 1

🧹 Nitpick comments (3)
src/app/dashboard/(active)/breadcrumb.tsx (1)

63-66: ⚡ Quick win

Replace hard-coded breadcrumb index rule with route-aware link eligibility.

Line 65 hard-codes i !== 1, which couples behavior to the current URL depth. Prefer deriving linkability from NAV_MAP so future route changes don’t break breadcrumb behavior.

Suggested diff
-    breadcrumbs.push({ title, url: i !== 1 ? currentPath : undefined })
+    const isNavigable = navMap.has(currentPath)
+    breadcrumbs.push({ title, url: isNavigable ? currentPath : undefined })
     i++
🤖 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 `@src/app/dashboard/`(active)/breadcrumb.tsx around lines 63 - 66, The
breadcrumb logic currently uses a hard-coded index check (i !== 1) when building
breadcrumb objects in breadcrumb.tsx; replace this with route-aware link
eligibility by consulting NAV_MAP (or the existing route metadata) instead of
relying on the iteration index. Locate where breadcrumbs.push({ title, url: i
!== 1 ? currentPath : undefined }) is used and change it to compute a boolean
like isLinkable = NAV_MAP[currentPath]?.linkable || NAV_MAP[currentPath]?.isPage
(or whatever metadata key denotes navigable pages) and then push { title, url:
isLinkable ? currentPath : undefined }; remove dependence on the variable
i/current depth so future route structure changes won’t break breadcrumb link
behavior.
src/hooks/use-cookie-storage.tsx (1)

28-46: ⚡ Quick win

Consider using functional setState to stabilize the setValue callback.

The current implementation includes storedValue in setValue's dependencies, causing a new callback reference on every state update. This can trigger unnecessary re-renders in components that receive setValue as a prop, and functional updates read from the closure rather than React's state queue.

♻️ Refactor to use functional setState
  const setValue: Dispatch<SetStateAction<T>> = useCallback(
    (value) => {
-     try {
-       const valueToStore = value instanceof Function ? value(storedValue) : value
-       setStoredValue(valueToStore)
-
-       if (typeof document !== "undefined") {
-         if (valueToStore === null || valueToStore === undefined) {
-           deleteCookie(key, { path: mergedOptions.path, domain: mergedOptions.domain })
-         } else {
-           setCookie(key, JSON.stringify(valueToStore), mergedOptions)
-         }
-       }
-     } catch (error) {
-       console.warn(`Error setting cookie "${key}":`, error)
-     }
+     try {
+       setStoredValue((prev) => {
+         const valueToStore = value instanceof Function ? value(prev) : value
+
+         if (typeof document !== "undefined") {
+           if (valueToStore === null || valueToStore === undefined) {
+             deleteCookie(key, { path: mergedOptions.path, domain: mergedOptions.domain })
+           } else {
+             setCookie(key, JSON.stringify(valueToStore), mergedOptions)
+           }
+         }
+
+         return valueToStore
+       })
+     } catch (error) {
+       console.warn(`Error setting cookie "${key}":`, error)
+     }
    },
-   [key, storedValue, mergedOptions]
+   [key, mergedOptions]
  )
🤖 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 `@src/hooks/use-cookie-storage.tsx` around lines 28 - 46, The setValue callback
closes over storedValue causing it to change identity on every state update;
change it to use the functional form of setStoredValue: inside useCallback call
setStoredValue(prev => { const valueToStore = value instanceof Function ?
value(prev) : value; /* update cookie/delete based on valueToStore */ return
valueToStore }); then remove storedValue from the useCallback dependency array
and keep key and mergedOptions, and continue using deleteCookie/setCookie with
mergedOptions and key; ensure cookie updates use the computed valueToStore
rather than the closed-over storedValue.
src/hooks/use-session-storage.tsx (1)

22-36: ⚡ Quick win

Consider using functional setState to stabilize the setValue callback.

Same issue as in use-cookie-storage.tsx: including storedValue in the dependencies array creates a new setValue reference on every state change. Using functional setState removes this dependency and ensures successive updates are properly chained through React's state queue.

♻️ Refactor to use functional setState
  const setValue: Dispatch<SetStateAction<T>> = useCallback(
    (value) => {
-     try {
-       const valueToStore = value instanceof Function ? value(storedValue) : value
-       setStoredValue(valueToStore)
-
-       if (typeof window !== "undefined") {
-         window.sessionStorage.setItem(key, JSON.stringify(valueToStore))
-       }
-     } catch (error) {
-       console.warn(`Error setting sessionStorage key "${key}":`, error)
-     }
+     try {
+       setStoredValue((prev) => {
+         const valueToStore = value instanceof Function ? value(prev) : value
+
+         if (typeof window !== "undefined") {
+           window.sessionStorage.setItem(key, JSON.stringify(valueToStore))
+         }
+
+         return valueToStore
+       })
+     } catch (error) {
+       console.warn(`Error setting sessionStorage key "${key}":`, error)
+     }
    },
-   [key, storedValue]
+   [key]
  )
🤖 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 `@src/hooks/use-session-storage.tsx` around lines 22 - 36, The setValue
callback currently closes over storedValue and lists it in the useCallback deps
which recreates setValue on every state change; change setValue (the function
passed to useCallback) to use functional setState with setStoredValue(prev => {
const valueToStore = typeof value === "function" ? value(prev) : value; /*
persist to sessionStorage using key */ return valueToStore; }) so you compute
valueToStore from the previous state instead of reading storedValue, then remove
storedValue from the dependency array so useCallback only depends on key; keep
the sessionStorage write (window.sessionStorage.setItem(key,
JSON.stringify(valueToStore))) and the existing try/catch and warning 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.

Inline comments:
In `@src/app/dashboard/`(active)/breadcrumb.tsx:
- Line 69: Remove the debug logging statement that prints route breadcrumbs to
the client: delete the console.log(breadcrumbs) call in
src/app/dashboard/(active)/breadcrumb.tsx (the place where the breadcrumbs
variable is used/rendered) so that user-facing code no longer outputs route
details; if needed for development replace it with a guarded debug logger that's
disabled in production or move logging behind a NODE_ENV check in the Breadcrumb
rendering logic.

---

Nitpick comments:
In `@src/app/dashboard/`(active)/breadcrumb.tsx:
- Around line 63-66: The breadcrumb logic currently uses a hard-coded index
check (i !== 1) when building breadcrumb objects in breadcrumb.tsx; replace this
with route-aware link eligibility by consulting NAV_MAP (or the existing route
metadata) instead of relying on the iteration index. Locate where
breadcrumbs.push({ title, url: i !== 1 ? currentPath : undefined }) is used and
change it to compute a boolean like isLinkable = NAV_MAP[currentPath]?.linkable
|| NAV_MAP[currentPath]?.isPage (or whatever metadata key denotes navigable
pages) and then push { title, url: isLinkable ? currentPath : undefined };
remove dependence on the variable i/current depth so future route structure
changes won’t break breadcrumb link behavior.

In `@src/hooks/use-cookie-storage.tsx`:
- Around line 28-46: The setValue callback closes over storedValue causing it to
change identity on every state update; change it to use the functional form of
setStoredValue: inside useCallback call setStoredValue(prev => { const
valueToStore = value instanceof Function ? value(prev) : value; /* update
cookie/delete based on valueToStore */ return valueToStore }); then remove
storedValue from the useCallback dependency array and keep key and
mergedOptions, and continue using deleteCookie/setCookie with mergedOptions and
key; ensure cookie updates use the computed valueToStore rather than the
closed-over storedValue.

In `@src/hooks/use-session-storage.tsx`:
- Around line 22-36: The setValue callback currently closes over storedValue and
lists it in the useCallback deps which recreates setValue on every state change;
change setValue (the function passed to useCallback) to use functional setState
with setStoredValue(prev => { const valueToStore = typeof value === "function" ?
value(prev) : value; /* persist to sessionStorage using key */ return
valueToStore; }) so you compute valueToStore from the previous state instead of
reading storedValue, then remove storedValue from the dependency array so
useCallback only depends on key; keep the sessionStorage write
(window.sessionStorage.setItem(key, JSON.stringify(valueToStore))) and the
existing try/catch and warning behavior.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20b31a27-f364-49fd-9b2a-70d335ddc6c2

📥 Commits

Reviewing files that changed from the base of the PR and between 454e9db and 075f156.

📒 Files selected for processing (8)
  • src/app/dashboard/(active)/account/page.tsx
  • src/app/dashboard/(active)/azure/page.tsx
  • src/app/dashboard/(active)/breadcrumb.tsx
  • src/components/dashboard-sidebar/data.tsx
  • src/components/dashboard-sidebar/main-nav.tsx
  • src/hooks/use-cookie-storage.tsx
  • src/hooks/use-session-storage.tsx
  • src/index.css
💤 Files with no reviewable changes (1)
  • src/app/dashboard/(active)/azure/page.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/app/dashboard/(active)/account/page.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/dashboard-sidebar/data.tsx
  • src/components/dashboard-sidebar/main-nav.tsx

Comment thread src/app/dashboard/(active)/breadcrumb.tsx Outdated
@lorenzocorallo lorenzocorallo added status: in progress Work is currently being done on this issue and removed status: needs review Issue or PR awaiting review labels Jun 10, 2026

@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: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server/actions/users.ts (1)

19-29: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add error handling for tRPC calls.

The function chains multiple async tRPC calls without try/catch blocks. If any call fails (network issues, backend errors, authorization failures), the function will throw an unhandled exception that bubbles to the caller. Consider wrapping the calls in try/catch to provide graceful error handling and logging.

🛡️ Proposed error handling pattern
 export async function getUserDetails(userId: number) {
+  try {
     const { user } = await trpc.tg.users.get.query({ userId })
     if (!user) return null
 
     const { roles, groupAdmin } = await trpc.tg.permissions.getRoles.query({ userId: user.id })
     const { messages } = await trpc.tg.messages.getLastByUser.query({ userId: user.id, limit: 15 })
     const audits = await trpc.tg.auditLog.getById.query({ targetId: user.id })
 
     const { grant } = await getUserGrant(user.id)
     return { roles, groupAdmin, user, messages, audits, grant }
+  } catch (error) {
+    console.error('Failed to fetch user details:', error)
+    throw error // or return null, depending on desired behavior
+  }
 }
🤖 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 `@src/server/actions/users.ts` around lines 19 - 29, getUserDetails currently
calls multiple async tRPC endpoints (trpc.tg.users.get.query,
trpc.tg.permissions.getRoles.query, trpc.tg.messages.getLastByUser.query,
trpc.tg.auditLog.getById.query) and getUserGrant without any error handling;
wrap the entire sequence in a try/catch inside getUserDetails, log the caught
error via your logging utility (or processLogger) with context (e.g.,
"getUserDetails failed for userId: ..."), and return a safe fallback (null or a
structured error object) so callers don’t receive unhandled exceptions; ensure
you still return existing successful results when possible or short-circuit if
the primary user fetch fails.
🧹 Nitpick comments (6)
src/app/dashboard/(active)/telegram/grants/delete-grant.tsx (1)

22-28: ⚡ Quick win

Remove commented code.

Instead of leaving the onDelete prop and its invocation as comments, remove them entirely. Commented code can create confusion and maintenance burden.

🧹 Proposed cleanup
-export function DeleteGrant({
-  userId,
-  // onDelete
-}: {
-  userId: number
-  // onDelete(): void
-}) {
+export function DeleteGrant({ userId }: { userId: number }) {
   const router = useRouter()
   const [open, setOpen] = useState(false)

And remove the commented call:

       else {
         toast.success("Grant interrupted successfully")
         router.refresh()
-        // onDelete()
       }

Also applies to: 42-42

🤖 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 `@src/app/dashboard/`(active)/telegram/grants/delete-grant.tsx around lines 22
- 28, Remove the leftover commented prop and invocation from the DeleteGrant
component: delete the commented onDelete prop declaration in the component
signature and remove any commented call to onDelete inside the component
(references around the DeleteGrant function and its JSX). Keep only the actual
userId prop and related logic so no commented code remains.
src/app/dashboard/(active)/telegram/users/[id]/card-user-grant.tsx (1)

8-16: ⚡ Quick win

Remove commented code.

Similar to DeleteGrant, the commented onDelete prop should be removed entirely rather than left as a comment.

🧹 Proposed cleanup
-export function UserGrantCard({
-  user,
-  grant,
-  //onDelete
-}: {
-  user: TgUser
-  grant: TgGrant
-  //onDelete(): void
-}) {
+export function UserGrantCard({ user, grant }: { user: TgUser; grant: TgGrant }) {
   return (
🤖 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 `@src/app/dashboard/`(active)/telegram/users/[id]/card-user-grant.tsx around
lines 8 - 16, Remove the leftover commented prop from the UserGrantCard
component: delete the commented onDelete prop in both the function signature and
the TypeScript props type so the component signature is clean (refer to
UserGrantCard and its props block where "//onDelete" and "//onDelete(): void"
are present), mirroring the cleanup done in DeleteGrant.
src/app/dashboard/(active)/telegram/users/page.tsx (1)

1-1: ⚡ Quick win

Remove unused import ViewIcon.

The ViewIcon import is unused; only Eye is referenced in the component.

♻️ Proposed fix
-import { Eye, ViewIcon } from "lucide-react"
+import { Eye } from "lucide-react"
🤖 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 `@src/app/dashboard/`(active)/telegram/users/page.tsx at line 1, The import
line currently imports both Eye and ViewIcon but ViewIcon is never used; update
the import statement that references Eye and ViewIcon to only import Eye (remove
ViewIcon from the named imports) and verify there are no remaining references to
ViewIcon elsewhere in the module (e.g., in the component rendering) before
committing.
src/server/actions/users.ts (2)

20-20: ⚡ Quick win

Simplify redundant object property shorthand.

The object property userId: userId can be simplified to just userId using ES6 shorthand.

♻️ Proposed simplification
-  const { user } = await trpc.tg.users.get.query({ userId: userId })
+  const { user } = await trpc.tg.users.get.query({ userId })
🤖 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 `@src/server/actions/users.ts` at line 20, Replace the redundant object
property in the trpc call: in the invocation of trpc.tg.users.get.query (the
expression "const { user } = await trpc.tg.users.get.query({ userId: userId
})"), use ES6 shorthand and pass { userId } instead of { userId: userId } to
simplify the object literal.

19-19: 💤 Low value

Consider adding explicit return type annotation.

While TypeScript infers the return type correctly, adding an explicit return type improves code documentation and catches potential type mismatches earlier.

🤖 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 `@src/server/actions/users.ts` at line 19, Add an explicit return type
annotation to the getUserDetails function declaration (export async function
getUserDetails(userId: number): Promise<...>) that matches the actual resolved
value returned by the function (e.g., Promise<User> or Promise<User | null>);
inspect the function's return statements or awaited calls to determine the
correct concrete type or union, import or reference the appropriate
User/UserDetails type if needed, and update the declaration so TypeScript
enforces and documents the expected return shape.
src/app/dashboard/(active)/telegram/users/[id]/remove-role.tsx (1)

37-37: ⚡ Quick win

Remove commented code.

The commented onDelete prop and its invocation should be removed entirely for consistency with the refactoring pattern.

🧹 Proposed cleanup
 export function RemoveRole({
   user,
   alreadyRoles,
-  // onDelete,
 }: {
   user: TgUser
   alreadyRoles: TgUserRole[]
-  // onDelete(): void
 }) {

And remove the commented call:

       else {
         toast.success("Role removed!")
         router.refresh()
-        // onDelete()
       }

Also applies to: 41-41, 73-73

🤖 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 `@src/app/dashboard/`(active)/telegram/users/[id]/remove-role.tsx at line 37,
Remove the leftover commented prop and call for onDelete in the RemoveRole
component: delete the commented "onDelete," in the component props (the
commented prop near the top) and remove any commented invocation of onDelete
(the commented call around where the delete handler is invoked, including the
one at lines ~41 and ~73). Ensure you only remove the commented references to
onDelete and leave the rest of the component JSX and logic unchanged.
🤖 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 `@src/app/dashboard/`(active)/account/loading.tsx:
- Around line 28-30: The loading fallback currently renders an interactive
NewPasskeyButton in loading.tsx which can trigger auth.passkey.addPasskey(...)
and cause duplicate creations; remove NewPasskeyButton from the fallback and
replace it with a non-interactive placeholder (e.g., a Skeleton or static
disabled UI) so no write actions or router.refresh() can occur while the page is
loading; locate the JSX in loading.tsx that renders <NewPasskeyButton /> and
remove or substitute it with a harmless, non-interactive element.

In `@src/app/dashboard/`(active)/layout.tsx:
- Around line 46-47: The code trusts parseCookie(...) for
sidebarCategoryStateCookie and sidebarOpenCookie but needs runtime validation;
update the layout to validate and coerce values: for sidebarOpenCookie use
parseCookie(sidebarOpenCookie) then convert to a boolean (true if value === true
or value === "true") and default to true for invalid values before assigning to
open, and for sidebarCategoryStateCookie use
parseCookie(sidebarCategoryStateCookie) then ensure it's a Record<string,
boolean> by iterating keys and only keeping keys with boolean values (or
coercing truthy/falsy to booleans) and defaulting to {} for invalid results
before assigning to state so SidebarProvider always receives the expected
shapes.

In `@src/app/dashboard/`(active)/telegram/users/[id]/page.tsx:
- Line 41: The displayed comment "Last messages (max 12):" is inconsistent with
the server action that fetches messages with limit: 15; update the UI text in
the JSX paragraph (the element rendering "Last messages (max 12):") to match the
query limit (e.g., "Last messages (max 15):") or alternatively change the server
action's fetch limit to 12 so both sides agree—locate the paragraph in the page
component and the server action where messages are fetched with limit: 15 and
make them consistent.
- Around line 10-12: TgUserDetails currently calls getUserDetails(parseInt(id,
10)) without validating the parsed id; add validation after extracting params
(in TgUserDetails) to detect non-numeric or NaN IDs (e.g., const userId =
parseInt(id, 10); if (!Number.isInteger(userId) || Number.isNaN(userId)) ...).
On invalid IDs, stop calling getUserDetails and return a clear fallback (render
an error message/invalid-ID UI, throw Next.js notFound(), or redirect) so the
page doesn't render an empty container when getUserDetails would be passed NaN.
- Line 25: The alreadyIn prop passed to NewGroupAdmin is built from
data.groupAdmin but uses g?.group.id ?? 0 which injects 0 for missing ids and
the outer ?? [] is unnecessary; update the expression that computes alreadyIn
(the value passed into NewGroupAdmin in page.tsx) to first filter out entries
with nullish group or group.id (e.g., data.groupAdmin.filter(g => g?.group?.id
!= null).map(g => g.group.id)) so only real group ids are included and remove
the redundant ?? [].
- Around line 16-68: The page currently only renders content when data is
truthy, so when getUserDetails returns null users see a blank page; update the
component in page.tsx to explicitly handle data === null and render a clear
"User not found" (or similar) message/UI instead of nothing. Locate the
rendering block that checks {data && (...)} and add an explicit branch (e.g., if
data === null) that returns a styled paragraph or card informing the user the
requested user does not exist; keep the existing rendering for when data is
present (UserInfoCard, UserGrantCard, GroupAdminCard, MessageCard, AuditLogCard)
unchanged.
- Around line 57-59: Remove the unnecessary React Suspense wrapper around
AuditLogCard in the render loop: AuditLogCard (export function in
src/app/.../card-audit-log.tsx) is synchronous and will never suspend, so delete
the <Suspense fallback={null} key={`${m.id}-${m.type}`}> ... </Suspense> wrapper
around AuditLogCard in page.tsx and render <AuditLogCard log={m} /> directly
(preserve the key on the list item/parent element if needed).

In `@src/app/dashboard/`(active)/telegram/users/page.tsx:
- Around line 41-43: The icon-only Button containing the Eye icon lacks
accessible text; update the Button usage in page.tsx so screen readers get
context by adding an aria-label (e.g., aria-label="View user" or similar) to the
Button component or include a visually-hidden span with descriptive text next to
the Eye icon; ensure you modify the Button element where Eye is rendered (the
Button and Eye usage) so the accessible label matches the button action.

---

Outside diff comments:
In `@src/server/actions/users.ts`:
- Around line 19-29: getUserDetails currently calls multiple async tRPC
endpoints (trpc.tg.users.get.query, trpc.tg.permissions.getRoles.query,
trpc.tg.messages.getLastByUser.query, trpc.tg.auditLog.getById.query) and
getUserGrant without any error handling; wrap the entire sequence in a try/catch
inside getUserDetails, log the caught error via your logging utility (or
processLogger) with context (e.g., "getUserDetails failed for userId: ..."), and
return a safe fallback (null or a structured error object) so callers don’t
receive unhandled exceptions; ensure you still return existing successful
results when possible or short-circuit if the primary user fetch fails.

---

Nitpick comments:
In `@src/app/dashboard/`(active)/telegram/grants/delete-grant.tsx:
- Around line 22-28: Remove the leftover commented prop and invocation from the
DeleteGrant component: delete the commented onDelete prop declaration in the
component signature and remove any commented call to onDelete inside the
component (references around the DeleteGrant function and its JSX). Keep only
the actual userId prop and related logic so no commented code remains.

In `@src/app/dashboard/`(active)/telegram/users/[id]/card-user-grant.tsx:
- Around line 8-16: Remove the leftover commented prop from the UserGrantCard
component: delete the commented onDelete prop in both the function signature and
the TypeScript props type so the component signature is clean (refer to
UserGrantCard and its props block where "//onDelete" and "//onDelete(): void"
are present), mirroring the cleanup done in DeleteGrant.

In `@src/app/dashboard/`(active)/telegram/users/[id]/remove-role.tsx:
- Line 37: Remove the leftover commented prop and call for onDelete in the
RemoveRole component: delete the commented "onDelete," in the component props
(the commented prop near the top) and remove any commented invocation of
onDelete (the commented call around where the delete handler is invoked,
including the one at lines ~41 and ~73). Ensure you only remove the commented
references to onDelete and leave the rest of the component JSX and logic
unchanged.

In `@src/app/dashboard/`(active)/telegram/users/page.tsx:
- Line 1: The import line currently imports both Eye and ViewIcon but ViewIcon
is never used; update the import statement that references Eye and ViewIcon to
only import Eye (remove ViewIcon from the named imports) and verify there are no
remaining references to ViewIcon elsewhere in the module (e.g., in the component
rendering) before committing.

In `@src/server/actions/users.ts`:
- Line 20: Replace the redundant object property in the trpc call: in the
invocation of trpc.tg.users.get.query (the expression "const { user } = await
trpc.tg.users.get.query({ userId: userId })"), use ES6 shorthand and pass {
userId } instead of { userId: userId } to simplify the object literal.
- Line 19: Add an explicit return type annotation to the getUserDetails function
declaration (export async function getUserDetails(userId: number): Promise<...>)
that matches the actual resolved value returned by the function (e.g.,
Promise<User> or Promise<User | null>); inspect the function's return statements
or awaited calls to determine the correct concrete type or union, import or
reference the appropriate User/UserDetails type if needed, and update the
declaration so TypeScript enforces and documents the expected return shape.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a2828203-168d-400b-8137-e82afcc9f628

📥 Commits

Reviewing files that changed from the base of the PR and between ba20b0b and 4797e44.

📒 Files selected for processing (31)
  • src/app/dashboard/(active)/account/loading.tsx
  • src/app/dashboard/(active)/azure/members/loading.tsx
  • src/app/dashboard/(active)/complete-profile.tsx
  • src/app/dashboard/(active)/layout.tsx
  • src/app/dashboard/(active)/page.tsx
  • src/app/dashboard/(active)/telegram/grants/delete-grant.tsx
  • src/app/dashboard/(active)/telegram/grants/loading.tsx
  • src/app/dashboard/(active)/telegram/grants/page.tsx
  • src/app/dashboard/(active)/telegram/groups/loading.tsx
  • src/app/dashboard/(active)/telegram/groups/page.tsx
  • src/app/dashboard/(active)/telegram/user-details/page.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/add-role.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/card-audit-log.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/card-group-admin.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/card-message.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/card-user-grant.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/card-user-info.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/delete-group-admin.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/loading.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/new-group-admin.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/page.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/remove-role.tsx
  • src/app/dashboard/(active)/telegram/users/loading.tsx
  • src/app/dashboard/(active)/telegram/users/page.tsx
  • src/components/dashboard-sidebar/data.tsx
  • src/components/dashboard-sidebar/main-nav.tsx
  • src/components/ui/sidebar.tsx
  • src/constants.ts
  • src/hooks/use-cookie-storage.tsx
  • src/index.css
  • src/server/actions/users.ts
💤 Files with no reviewable changes (1)
  • src/app/dashboard/(active)/telegram/user-details/page.tsx
✅ Files skipped from review due to trivial changes (6)
  • src/app/dashboard/(active)/azure/members/loading.tsx
  • src/app/dashboard/(active)/telegram/groups/loading.tsx
  • src/app/dashboard/(active)/telegram/grants/loading.tsx
  • src/app/dashboard/(active)/telegram/users/[id]/loading.tsx
  • src/app/dashboard/(active)/telegram/groups/page.tsx
  • src/app/dashboard/(active)/telegram/users/loading.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/constants.ts
  • src/app/dashboard/(active)/telegram/grants/page.tsx
  • src/index.css
  • src/hooks/use-cookie-storage.tsx
  • src/components/dashboard-sidebar/data.tsx
  • src/components/ui/sidebar.tsx
  • src/components/dashboard-sidebar/main-nav.tsx

Comment thread src/app/dashboard/(active)/account/loading.tsx
Comment thread src/app/dashboard/(active)/layout.tsx
Comment thread src/app/dashboard/(active)/telegram/users/[id]/page.tsx Outdated
Comment thread src/app/dashboard/(active)/telegram/users/[id]/page.tsx
Comment thread src/app/dashboard/(active)/telegram/users/[id]/page.tsx Outdated
Comment thread src/app/dashboard/(active)/telegram/users/[id]/page.tsx Outdated
Comment thread src/app/dashboard/(active)/telegram/users/[id]/page.tsx Outdated
Comment thread src/app/dashboard/(active)/telegram/users/page.tsx Outdated
@lorenzocorallo lorenzocorallo added status: needs review Issue or PR awaiting review and removed status: in progress Work is currently being done on this issue labels Jun 10, 2026
@lorenzocorallo lorenzocorallo requested a review from BIA3IA June 10, 2026 22:34
BIA3IA
BIA3IA previously requested changes Jun 11, 2026
Comment thread src/app/dashboard/(active)/telegram/users/[id]/page.tsx Outdated
Comment thread src/app/dashboard/(active)/telegram/users/[id]/page.tsx
@BIA3IA BIA3IA dismissed their stale review June 11, 2026 10:40

Done

@BIA3IA BIA3IA merged commit 05f48c8 into main Jun 11, 2026
2 checks passed
@BIA3IA BIA3IA deleted the sidebar branch June 11, 2026 10:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: frontend Relates to frontend or user interface code status: needs review Issue or PR awaiting review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants