feat: add user selection functionality for suggestions and update API… - #39

Merged
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões
Aug 26, 2025

Hidden character warning

The head ref may contain hidden characters: "34-adicionar-caixa-de-sugest\u00f5es"
Merged

feat: add user selection functionality for suggestions and update API…#39
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões

Conversation

@rbxyz

@rbxyzrbxyz commented Aug 26, 2025

Copy link
Copy Markdown
Collaborator

… to include analystId

Summary by CodeRabbit

  • New Features

    • Assign a responsible analyst to each suggestion using a user picker, with support for selecting or clearing (“Não atribuído”).
  • Improvements

    • Suggestions now consistently display the assigned analyst where applicable.
    • Clearer user identification in the picker (full name or email).
    • Minor UI refinements with improved dropdown indicators.

@vercel

vercelBot commented Aug 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
eloReadyReadyPreviewCommentAug 26, 2025 1:50pm

@coderabbitai

coderabbitaiBot commented Aug 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds analyst assignment support for suggestions: frontend introduces a UserSelector to set analystId per suggestion and threads _currentUser; backend expands admin list selection fields and updates admin update mutation to accept optional analystId, defaulting to the current user when not provided.

Changes

Cohort / File(s)Summary
Admin suggestions UI and data flow
src/app/(authenticated)/admin/suggestions/page.tsx
Adds analystId to local model; maps db analystId; introduces UserSelector (Popover + Command) to assign/clear analyst; wires update payload to include analystId; renames/passes _currentUser; replaces static responsible display with UserSelector; imports icons/components; minor console logging.
Suggestions API (admin endpoints)
src/server/api/routers/suggestions.ts
Admin list now uses select and returns expanded fields plus nested user/analyst; updateAdmin input adds optional analystId; update uses input.analystId or falls back to ctx.auth.userId; comment updated; non-admin flows unchanged.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Admin as Admin User
participant UI as AdminSuggestionsPage
participant Sel as UserSelector
participant API as tRPC: suggestions
participant DB as Database
Admin->>UI: Open admin suggestions
UI->>API: listAdmin()
API->>DB: SELECT id,...,analystId, user{...}, analyst{...}
DB-->>API: Rows
API-->>UI: Suggestions with analyst and user data
Admin->>Sel: Open analyst selector
Sel->>API: user.listAll()
API->>DB: SELECT users
DB-->>API: Users
API-->>Sel: Users list
Admin->>Sel: Choose analyst (or "Não atribuído")
Sel-->>UI: onValueChange(analystId|null)
UI->>API: updateAdmin({ id, ..., analystId? })
API->>DB: UPDATE suggestion SET analystId = input.analystId ?? ctx.auth.userId
DB-->>API: OK
API-->>UI: Updated suggestion
UI-->>Admin: Reflect updated responsible analyst
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers at the queue,
Assigning minds to ideas anew.
A hop, a click—analysts align,
The backend nods, selects refine.
With gentle thumps I mark the trail,
Suggestions sorted—cotton-tail. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 34-adicionar-caixa-de-sugestões

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/app/(authenticated)/admin/suggestions/page.tsx (1)

367-383: Preserve null for analystId; don’t coerce to undefined

Coercing null to undefined breaks unassigning semantics and, combined with the server’s current fallback, will reassign to the current admin. Keep null intact.

Apply:

- if (updates.analystId !== undefined) {- updateData.analystId = updates.analystId ?? undefined- }+ if (updates.analystId !== undefined) {+ // Keep null to explicitly clear assignment; undefined means no change+ updateData.analystId = updates.analystId+ }
🧹 Nitpick comments (6)
src/server/api/routers/suggestions.ts (1)

110-127: Good switch to explicit select; consider trimming unused fields to reduce payload

Nice move to an explicit select for admin list; this typically improves performance and keeps types tight. If the UI ultimately displays the user's sector (user.setor) instead of the submitted sector, consider dropping submittedSector from the selection to cut payload, or align the mapping to avoid confusion.

Example minimal trim:

 select: {
id: true,
ideaNumber: true,
submittedName: true,
- submittedSector: true,
isNameVisible: true,
description: true,
contribution: true,
dateRef: true,
impact: true,
capacity: true,
effort: true,
finalScore: true,
finalClassification: true,
status: true,
rejectionReason: true,
analystId: true,
createdAt: true,
user: {
select: {
firstName: true,
lastName: true,
email: true,
setor: true,
},
},
analyst: {
select: {
firstName: true,
lastName: true,
email: true,
},
},
},
src/app/(authenticated)/admin/suggestions/page.tsx (5)

44-45: Type captures the new responsibility concept; document tri-state intent

Defining analystId: string | null in SuggestionLocal is fine. For clarity and to align with the server change, ensure the app treats:

  • undefined: no change
  • string: assign to that user
  • null: unassign

Would you like me to sweep the components for places where analystId is constructed to ensure they adhere to this tri-state convention?


222-222: _currentUser is fetched but never used; avoid prop drilling

_currentUser is passed down multiple levels but not used. Either remove it to reduce churn, or leverage it (e.g., to show “Você” next to the current user in UserSelector).


612-612: Remove unused _currentUser prop passed through components

_currentUser is threaded through IdeasAccordion and SuggestionItem but unused. Trim these props to simplify component signatures and avoid unnecessary rerenders.

High-level diff outline:

- _currentUser={_currentUser}

And in component props:

- _currentUser: RouterOutputs["user"]["me"] | undefined

Also applies to: 630-630, 689-689, 701-701, 779-779, 806-806


1040-1044: Unassign flow and UX: ensure it works end-to-end and consider disabling while saving

This call path must allow setting analystId to null. With the client/server fixes above, the “Não atribuído” option will clear the assignment. Consider temporarily disabling the selector while the update mutation for this suggestion is in-flight to avoid rapid toggles causing racey UI.

Example (conceptual; needs plumbing of a per-suggestion pending state):

- <UserSelector+ <UserSelector
value={s.analystId}
- onValueChange={(userId: string | null) => {+ onValueChange={(userId: string | null) => {
update(s.id, { analystId: userId })
}}
- />+ disabled={/* pending state for this suggestion's update */}+ />

129-215: Ensure “Não atribuído” shows selected state, improve typing, scalability, and confirm security

Selected state
The “Não atribuído” item should display a checkmark when value === null, matching the behavior of other rows.

Typing
Update getUserDisplayName to use (typeof allUsers)[number] so the parameter type can never be undefined.

Scalability
Currently api.user.listAll.useQuery() fetches every user on mount. If the user count grows, consider switching to a server-side search or paginated endpoint to keep the popover performant.

Security
Verified that user.listAll is implemented with adminProcedure in src/server/api/routers/user.ts (lines 21–23), so only admins can call it.

Apply these optional refactors:

- const getUserDisplayName = (user: typeof allUsers[0]) => {+ const getUserDisplayName = (user: (typeof allUsers)[number]) => {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`
}
return user.email
}
 <CommandItem
onSelect={() => {
onValueChange(null)
setOpen(false)
}}
className="text-muted-foreground"
>
- <Check className="mr-2 h-4 w-4 opacity-0" />+ <Check className={`mr-2 h-4 w-4 ${value === null ? "opacity-100" : "opacity-0"}`} />
Não atribuído
</CommandItem>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0891924 and 1728631.

📒 Files selected for processing (2)
  • src/app/(authenticated)/admin/suggestions/page.tsx (15 hunks)
  • src/server/api/routers/suggestions.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/(authenticated)/admin/suggestions/page.tsx (4)
src/trpc/react.tsx (2)
  • api (23-23)
  • RouterOutputs (37-37)
src/components/ui/popover.tsx (3)
  • Popover (31-31)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/components/ui/command.tsx (6)
  • Command (144-144)
  • CommandInput (146-146)
  • CommandList (147-147)
  • CommandEmpty (148-148)
  • CommandGroup (149-149)
  • CommandItem (150-150)
🔇 Additional comments (5)
src/server/api/routers/suggestions.ts (1)

162-162: Comment update improves clarity

The updated doc comment calling out analyst handling is helpful for future readers.

src/app/(authenticated)/admin/suggestions/page.tsx (4)

18-18: Icon import looks good

Imports are consistent with usage in this file.


20-21: Command/Popover UI imports are appropriate

Matches the new UserSelector implementation below.


113-113: Mapping analystId from DB is correct

Direct pass-through matches the server select.


313-338: Classification pools: good memoized mapping

Mapping tRPC results to local ClassItem[] is straightforward and readable.

kpis: z.array(z.string()).optional(),
status: StatusEnum.optional(),
rejectionReason: z.string().optional(),
analystId: z.string().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow null to enable unassigning an analyst (tri-state: string | null | undefined)

Right now analystId is z.string().optional(). That makes it impossible to intentionally clear the responsible analyst: sending null fails validation; omitting the field (undefined) currently triggers a fallback (see Line 240) that will force-assign the current admin. Support null so the client can unassign.

Apply:

- analystId: z.string().optional(),+ // string = assign to user; null = unassign; undefined = do not change+ analystId: z.string().nullable().optional(),
📝 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.

Suggested change
analystId: z.string().optional(),
// string = assign to user; null = unassign; undefined = do not change
analystId: z.string().nullable().optional(),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 172, the Zod schema for
analystId should accept null so clients can explicitly unassign; change the
schema to allow string | null | undefined (e.g., make it nullable and optional).
Also adjust the handling around line 240 so the "fallback to current admin" only
runs when analystId is strictly undefined (preserve existing behavior for
omitted field) and treat a null value as an explicit unassign (do not replace it
with the current admin).

status: input.status,
rejectionReason: input.rejectionReason,
analystId: ctx.auth.userId,
analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not force-assign analyst on every admin update; honor undefined vs null

analystId: input.analystId ?? ctx.auth.userId reassigns the analyst to the current admin on any update that omits analystId. It also prevents unassigning even if the client sends null (because ?? coalesces null). This will silently overwrite the responsible analyst during unrelated updates (status, scores, etc.).

Use tri-state semantics:

  • undefined: don't touch analystId
  • string: assign to that user
  • null: clear the assignment

Apply:

- analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual+ // Only modify when provided; allow null to clear+ ...(input.analystId !== undefined ? { analystId: input.analystId } : {}),

Optionally, if you want a one-time default assignment when there is no analyst yet, gate it explicitly:

// Before update, fetch current analystIdconstcurrent=awaitctx.db.suggestion.findUnique({where: {id: input.id},select: {analystId: true}});// In data:
...(input.analystId!==undefined
? {analystId: input.analystId}
: current?.analystId ? {} : {/* decide whether to set a default here or leave null */}),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 240, the current use of
"analystId: input.analystId ?? ctx.auth.userId" force-assigns the analyst on
every update and treats null as undefined; change this to tri-state handling:
fetch the current suggestion's analystId first, then when building the update
data only include analystId if input.analystId !== undefined (if string, set it;
if null, set it to null to clear), and do not fall back to ctx.auth.userId
implicitly — if you want a one-time default when there is no analyst, gate that
explicitly based on the fetched current value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rbxyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: add user selection functionality for suggestions and update API… - #39

Merged
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões
Aug 26, 2025

Hidden character warning

The head ref may contain hidden characters: "34-adicionar-caixa-de-sugest\u00f5es"
Merged

feat: add user selection functionality for suggestions and update API…#39
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões

Conversation

@rbxyz

@rbxyzrbxyz commented Aug 26, 2025

Copy link
Copy Markdown
Collaborator

… to include analystId

Summary by CodeRabbit

  • New Features

    • Assign a responsible analyst to each suggestion using a user picker, with support for selecting or clearing (“Não atribuído”).
  • Improvements

    • Suggestions now consistently display the assigned analyst where applicable.
    • Clearer user identification in the picker (full name or email).
    • Minor UI refinements with improved dropdown indicators.

@vercel

vercelBot commented Aug 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
eloReadyReadyPreviewCommentAug 26, 2025 1:50pm

@coderabbitai

coderabbitaiBot commented Aug 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds analyst assignment support for suggestions: frontend introduces a UserSelector to set analystId per suggestion and threads _currentUser; backend expands admin list selection fields and updates admin update mutation to accept optional analystId, defaulting to the current user when not provided.

Changes

Cohort / File(s)Summary
Admin suggestions UI and data flow
src/app/(authenticated)/admin/suggestions/page.tsx
Adds analystId to local model; maps db analystId; introduces UserSelector (Popover + Command) to assign/clear analyst; wires update payload to include analystId; renames/passes _currentUser; replaces static responsible display with UserSelector; imports icons/components; minor console logging.
Suggestions API (admin endpoints)
src/server/api/routers/suggestions.ts
Admin list now uses select and returns expanded fields plus nested user/analyst; updateAdmin input adds optional analystId; update uses input.analystId or falls back to ctx.auth.userId; comment updated; non-admin flows unchanged.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Admin as Admin User
participant UI as AdminSuggestionsPage
participant Sel as UserSelector
participant API as tRPC: suggestions
participant DB as Database
Admin->>UI: Open admin suggestions
UI->>API: listAdmin()
API->>DB: SELECT id,...,analystId, user{...}, analyst{...}
DB-->>API: Rows
API-->>UI: Suggestions with analyst and user data
Admin->>Sel: Open analyst selector
Sel->>API: user.listAll()
API->>DB: SELECT users
DB-->>API: Users
API-->>Sel: Users list
Admin->>Sel: Choose analyst (or "Não atribuído")
Sel-->>UI: onValueChange(analystId|null)
UI->>API: updateAdmin({ id, ..., analystId? })
API->>DB: UPDATE suggestion SET analystId = input.analystId ?? ctx.auth.userId
DB-->>API: OK
API-->>UI: Updated suggestion
UI-->>Admin: Reflect updated responsible analyst
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers at the queue,
Assigning minds to ideas anew.
A hop, a click—analysts align,
The backend nods, selects refine.
With gentle thumps I mark the trail,
Suggestions sorted—cotton-tail. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 34-adicionar-caixa-de-sugestões

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/app/(authenticated)/admin/suggestions/page.tsx (1)

367-383: Preserve null for analystId; don’t coerce to undefined

Coercing null to undefined breaks unassigning semantics and, combined with the server’s current fallback, will reassign to the current admin. Keep null intact.

Apply:

- if (updates.analystId !== undefined) {- updateData.analystId = updates.analystId ?? undefined- }+ if (updates.analystId !== undefined) {+ // Keep null to explicitly clear assignment; undefined means no change+ updateData.analystId = updates.analystId+ }
🧹 Nitpick comments (6)
src/server/api/routers/suggestions.ts (1)

110-127: Good switch to explicit select; consider trimming unused fields to reduce payload

Nice move to an explicit select for admin list; this typically improves performance and keeps types tight. If the UI ultimately displays the user's sector (user.setor) instead of the submitted sector, consider dropping submittedSector from the selection to cut payload, or align the mapping to avoid confusion.

Example minimal trim:

 select: {
id: true,
ideaNumber: true,
submittedName: true,
- submittedSector: true,
isNameVisible: true,
description: true,
contribution: true,
dateRef: true,
impact: true,
capacity: true,
effort: true,
finalScore: true,
finalClassification: true,
status: true,
rejectionReason: true,
analystId: true,
createdAt: true,
user: {
select: {
firstName: true,
lastName: true,
email: true,
setor: true,
},
},
analyst: {
select: {
firstName: true,
lastName: true,
email: true,
},
},
},
src/app/(authenticated)/admin/suggestions/page.tsx (5)

44-45: Type captures the new responsibility concept; document tri-state intent

Defining analystId: string | null in SuggestionLocal is fine. For clarity and to align with the server change, ensure the app treats:

  • undefined: no change
  • string: assign to that user
  • null: unassign

Would you like me to sweep the components for places where analystId is constructed to ensure they adhere to this tri-state convention?


222-222: _currentUser is fetched but never used; avoid prop drilling

_currentUser is passed down multiple levels but not used. Either remove it to reduce churn, or leverage it (e.g., to show “Você” next to the current user in UserSelector).


612-612: Remove unused _currentUser prop passed through components

_currentUser is threaded through IdeasAccordion and SuggestionItem but unused. Trim these props to simplify component signatures and avoid unnecessary rerenders.

High-level diff outline:

- _currentUser={_currentUser}

And in component props:

- _currentUser: RouterOutputs["user"]["me"] | undefined

Also applies to: 630-630, 689-689, 701-701, 779-779, 806-806


1040-1044: Unassign flow and UX: ensure it works end-to-end and consider disabling while saving

This call path must allow setting analystId to null. With the client/server fixes above, the “Não atribuído” option will clear the assignment. Consider temporarily disabling the selector while the update mutation for this suggestion is in-flight to avoid rapid toggles causing racey UI.

Example (conceptual; needs plumbing of a per-suggestion pending state):

- <UserSelector+ <UserSelector
value={s.analystId}
- onValueChange={(userId: string | null) => {+ onValueChange={(userId: string | null) => {
update(s.id, { analystId: userId })
}}
- />+ disabled={/* pending state for this suggestion's update */}+ />

129-215: Ensure “Não atribuído” shows selected state, improve typing, scalability, and confirm security

Selected state
The “Não atribuído” item should display a checkmark when value === null, matching the behavior of other rows.

Typing
Update getUserDisplayName to use (typeof allUsers)[number] so the parameter type can never be undefined.

Scalability
Currently api.user.listAll.useQuery() fetches every user on mount. If the user count grows, consider switching to a server-side search or paginated endpoint to keep the popover performant.

Security
Verified that user.listAll is implemented with adminProcedure in src/server/api/routers/user.ts (lines 21–23), so only admins can call it.

Apply these optional refactors:

- const getUserDisplayName = (user: typeof allUsers[0]) => {+ const getUserDisplayName = (user: (typeof allUsers)[number]) => {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`
}
return user.email
}
 <CommandItem
onSelect={() => {
onValueChange(null)
setOpen(false)
}}
className="text-muted-foreground"
>
- <Check className="mr-2 h-4 w-4 opacity-0" />+ <Check className={`mr-2 h-4 w-4 ${value === null ? "opacity-100" : "opacity-0"}`} />
Não atribuído
</CommandItem>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0891924 and 1728631.

📒 Files selected for processing (2)
  • src/app/(authenticated)/admin/suggestions/page.tsx (15 hunks)
  • src/server/api/routers/suggestions.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/(authenticated)/admin/suggestions/page.tsx (4)
src/trpc/react.tsx (2)
  • api (23-23)
  • RouterOutputs (37-37)
src/components/ui/popover.tsx (3)
  • Popover (31-31)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/components/ui/command.tsx (6)
  • Command (144-144)
  • CommandInput (146-146)
  • CommandList (147-147)
  • CommandEmpty (148-148)
  • CommandGroup (149-149)
  • CommandItem (150-150)
🔇 Additional comments (5)
src/server/api/routers/suggestions.ts (1)

162-162: Comment update improves clarity

The updated doc comment calling out analyst handling is helpful for future readers.

src/app/(authenticated)/admin/suggestions/page.tsx (4)

18-18: Icon import looks good

Imports are consistent with usage in this file.


20-21: Command/Popover UI imports are appropriate

Matches the new UserSelector implementation below.


113-113: Mapping analystId from DB is correct

Direct pass-through matches the server select.


313-338: Classification pools: good memoized mapping

Mapping tRPC results to local ClassItem[] is straightforward and readable.

kpis: z.array(z.string()).optional(),
status: StatusEnum.optional(),
rejectionReason: z.string().optional(),
analystId: z.string().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow null to enable unassigning an analyst (tri-state: string | null | undefined)

Right now analystId is z.string().optional(). That makes it impossible to intentionally clear the responsible analyst: sending null fails validation; omitting the field (undefined) currently triggers a fallback (see Line 240) that will force-assign the current admin. Support null so the client can unassign.

Apply:

- analystId: z.string().optional(),+ // string = assign to user; null = unassign; undefined = do not change+ analystId: z.string().nullable().optional(),
📝 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.

Suggested change
analystId: z.string().optional(),
// string = assign to user; null = unassign; undefined = do not change
analystId: z.string().nullable().optional(),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 172, the Zod schema for
analystId should accept null so clients can explicitly unassign; change the
schema to allow string | null | undefined (e.g., make it nullable and optional).
Also adjust the handling around line 240 so the "fallback to current admin" only
runs when analystId is strictly undefined (preserve existing behavior for
omitted field) and treat a null value as an explicit unassign (do not replace it
with the current admin).

status: input.status,
rejectionReason: input.rejectionReason,
analystId: ctx.auth.userId,
analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not force-assign analyst on every admin update; honor undefined vs null

analystId: input.analystId ?? ctx.auth.userId reassigns the analyst to the current admin on any update that omits analystId. It also prevents unassigning even if the client sends null (because ?? coalesces null). This will silently overwrite the responsible analyst during unrelated updates (status, scores, etc.).

Use tri-state semantics:

  • undefined: don't touch analystId
  • string: assign to that user
  • null: clear the assignment

Apply:

- analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual+ // Only modify when provided; allow null to clear+ ...(input.analystId !== undefined ? { analystId: input.analystId } : {}),

Optionally, if you want a one-time default assignment when there is no analyst yet, gate it explicitly:

// Before update, fetch current analystIdconstcurrent=awaitctx.db.suggestion.findUnique({where: {id: input.id},select: {analystId: true}});// In data:
...(input.analystId!==undefined
? {analystId: input.analystId}
: current?.analystId ? {} : {/* decide whether to set a default here or leave null */}),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 240, the current use of
"analystId: input.analystId ?? ctx.auth.userId" force-assigns the analyst on
every update and treats null as undefined; change this to tri-state handling:
fetch the current suggestion's analystId first, then when building the update
data only include analystId if input.analystId !== undefined (if string, set it;
if null, set it to null to clear), and do not fall back to ctx.auth.userId
implicitly — if you want a one-time default when there is no analyst, gate that
explicitly based on the fetched current value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rbxyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add user selection functionality for suggestions and update API… - #39

Merged
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões
Aug 26, 2025

Hidden character warning

The head ref may contain hidden characters: "34-adicionar-caixa-de-sugest\u00f5es"
Merged

feat: add user selection functionality for suggestions and update API…#39
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões

Conversation

@rbxyz

@rbxyzrbxyz commented Aug 26, 2025

Copy link
Copy Markdown
Collaborator

… to include analystId

Summary by CodeRabbit

  • New Features

    • Assign a responsible analyst to each suggestion using a user picker, with support for selecting or clearing (“Não atribuído”).
  • Improvements

    • Suggestions now consistently display the assigned analyst where applicable.
    • Clearer user identification in the picker (full name or email).
    • Minor UI refinements with improved dropdown indicators.

@vercel

vercelBot commented Aug 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
eloReadyReadyPreviewCommentAug 26, 2025 1:50pm

@coderabbitai

coderabbitaiBot commented Aug 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds analyst assignment support for suggestions: frontend introduces a UserSelector to set analystId per suggestion and threads _currentUser; backend expands admin list selection fields and updates admin update mutation to accept optional analystId, defaulting to the current user when not provided.

Changes

Cohort / File(s)Summary
Admin suggestions UI and data flow
src/app/(authenticated)/admin/suggestions/page.tsx
Adds analystId to local model; maps db analystId; introduces UserSelector (Popover + Command) to assign/clear analyst; wires update payload to include analystId; renames/passes _currentUser; replaces static responsible display with UserSelector; imports icons/components; minor console logging.
Suggestions API (admin endpoints)
src/server/api/routers/suggestions.ts
Admin list now uses select and returns expanded fields plus nested user/analyst; updateAdmin input adds optional analystId; update uses input.analystId or falls back to ctx.auth.userId; comment updated; non-admin flows unchanged.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Admin as Admin User
participant UI as AdminSuggestionsPage
participant Sel as UserSelector
participant API as tRPC: suggestions
participant DB as Database
Admin->>UI: Open admin suggestions
UI->>API: listAdmin()
API->>DB: SELECT id,...,analystId, user{...}, analyst{...}
DB-->>API: Rows
API-->>UI: Suggestions with analyst and user data
Admin->>Sel: Open analyst selector
Sel->>API: user.listAll()
API->>DB: SELECT users
DB-->>API: Users
API-->>Sel: Users list
Admin->>Sel: Choose analyst (or "Não atribuído")
Sel-->>UI: onValueChange(analystId|null)
UI->>API: updateAdmin({ id, ..., analystId? })
API->>DB: UPDATE suggestion SET analystId = input.analystId ?? ctx.auth.userId
DB-->>API: OK
API-->>UI: Updated suggestion
UI-->>Admin: Reflect updated responsible analyst
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers at the queue,
Assigning minds to ideas anew.
A hop, a click—analysts align,
The backend nods, selects refine.
With gentle thumps I mark the trail,
Suggestions sorted—cotton-tail. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 34-adicionar-caixa-de-sugestões

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/app/(authenticated)/admin/suggestions/page.tsx (1)

367-383: Preserve null for analystId; don’t coerce to undefined

Coercing null to undefined breaks unassigning semantics and, combined with the server’s current fallback, will reassign to the current admin. Keep null intact.

Apply:

- if (updates.analystId !== undefined) {- updateData.analystId = updates.analystId ?? undefined- }+ if (updates.analystId !== undefined) {+ // Keep null to explicitly clear assignment; undefined means no change+ updateData.analystId = updates.analystId+ }
🧹 Nitpick comments (6)
src/server/api/routers/suggestions.ts (1)

110-127: Good switch to explicit select; consider trimming unused fields to reduce payload

Nice move to an explicit select for admin list; this typically improves performance and keeps types tight. If the UI ultimately displays the user's sector (user.setor) instead of the submitted sector, consider dropping submittedSector from the selection to cut payload, or align the mapping to avoid confusion.

Example minimal trim:

 select: {
id: true,
ideaNumber: true,
submittedName: true,
- submittedSector: true,
isNameVisible: true,
description: true,
contribution: true,
dateRef: true,
impact: true,
capacity: true,
effort: true,
finalScore: true,
finalClassification: true,
status: true,
rejectionReason: true,
analystId: true,
createdAt: true,
user: {
select: {
firstName: true,
lastName: true,
email: true,
setor: true,
},
},
analyst: {
select: {
firstName: true,
lastName: true,
email: true,
},
},
},
src/app/(authenticated)/admin/suggestions/page.tsx (5)

44-45: Type captures the new responsibility concept; document tri-state intent

Defining analystId: string | null in SuggestionLocal is fine. For clarity and to align with the server change, ensure the app treats:

  • undefined: no change
  • string: assign to that user
  • null: unassign

Would you like me to sweep the components for places where analystId is constructed to ensure they adhere to this tri-state convention?


222-222: _currentUser is fetched but never used; avoid prop drilling

_currentUser is passed down multiple levels but not used. Either remove it to reduce churn, or leverage it (e.g., to show “Você” next to the current user in UserSelector).


612-612: Remove unused _currentUser prop passed through components

_currentUser is threaded through IdeasAccordion and SuggestionItem but unused. Trim these props to simplify component signatures and avoid unnecessary rerenders.

High-level diff outline:

- _currentUser={_currentUser}

And in component props:

- _currentUser: RouterOutputs["user"]["me"] | undefined

Also applies to: 630-630, 689-689, 701-701, 779-779, 806-806


1040-1044: Unassign flow and UX: ensure it works end-to-end and consider disabling while saving

This call path must allow setting analystId to null. With the client/server fixes above, the “Não atribuído” option will clear the assignment. Consider temporarily disabling the selector while the update mutation for this suggestion is in-flight to avoid rapid toggles causing racey UI.

Example (conceptual; needs plumbing of a per-suggestion pending state):

- <UserSelector+ <UserSelector
value={s.analystId}
- onValueChange={(userId: string | null) => {+ onValueChange={(userId: string | null) => {
update(s.id, { analystId: userId })
}}
- />+ disabled={/* pending state for this suggestion's update */}+ />

129-215: Ensure “Não atribuído” shows selected state, improve typing, scalability, and confirm security

Selected state
The “Não atribuído” item should display a checkmark when value === null, matching the behavior of other rows.

Typing
Update getUserDisplayName to use (typeof allUsers)[number] so the parameter type can never be undefined.

Scalability
Currently api.user.listAll.useQuery() fetches every user on mount. If the user count grows, consider switching to a server-side search or paginated endpoint to keep the popover performant.

Security
Verified that user.listAll is implemented with adminProcedure in src/server/api/routers/user.ts (lines 21–23), so only admins can call it.

Apply these optional refactors:

- const getUserDisplayName = (user: typeof allUsers[0]) => {+ const getUserDisplayName = (user: (typeof allUsers)[number]) => {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`
}
return user.email
}
 <CommandItem
onSelect={() => {
onValueChange(null)
setOpen(false)
}}
className="text-muted-foreground"
>
- <Check className="mr-2 h-4 w-4 opacity-0" />+ <Check className={`mr-2 h-4 w-4 ${value === null ? "opacity-100" : "opacity-0"}`} />
Não atribuído
</CommandItem>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0891924 and 1728631.

📒 Files selected for processing (2)
  • src/app/(authenticated)/admin/suggestions/page.tsx (15 hunks)
  • src/server/api/routers/suggestions.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/(authenticated)/admin/suggestions/page.tsx (4)
src/trpc/react.tsx (2)
  • api (23-23)
  • RouterOutputs (37-37)
src/components/ui/popover.tsx (3)
  • Popover (31-31)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/components/ui/command.tsx (6)
  • Command (144-144)
  • CommandInput (146-146)
  • CommandList (147-147)
  • CommandEmpty (148-148)
  • CommandGroup (149-149)
  • CommandItem (150-150)
🔇 Additional comments (5)
src/server/api/routers/suggestions.ts (1)

162-162: Comment update improves clarity

The updated doc comment calling out analyst handling is helpful for future readers.

src/app/(authenticated)/admin/suggestions/page.tsx (4)

18-18: Icon import looks good

Imports are consistent with usage in this file.


20-21: Command/Popover UI imports are appropriate

Matches the new UserSelector implementation below.


113-113: Mapping analystId from DB is correct

Direct pass-through matches the server select.


313-338: Classification pools: good memoized mapping

Mapping tRPC results to local ClassItem[] is straightforward and readable.

kpis: z.array(z.string()).optional(),
status: StatusEnum.optional(),
rejectionReason: z.string().optional(),
analystId: z.string().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow null to enable unassigning an analyst (tri-state: string | null | undefined)

Right now analystId is z.string().optional(). That makes it impossible to intentionally clear the responsible analyst: sending null fails validation; omitting the field (undefined) currently triggers a fallback (see Line 240) that will force-assign the current admin. Support null so the client can unassign.

Apply:

- analystId: z.string().optional(),+ // string = assign to user; null = unassign; undefined = do not change+ analystId: z.string().nullable().optional(),
📝 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.

Suggested change
analystId: z.string().optional(),
// string = assign to user; null = unassign; undefined = do not change
analystId: z.string().nullable().optional(),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 172, the Zod schema for
analystId should accept null so clients can explicitly unassign; change the
schema to allow string | null | undefined (e.g., make it nullable and optional).
Also adjust the handling around line 240 so the "fallback to current admin" only
runs when analystId is strictly undefined (preserve existing behavior for
omitted field) and treat a null value as an explicit unassign (do not replace it
with the current admin).

status: input.status,
rejectionReason: input.rejectionReason,
analystId: ctx.auth.userId,
analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not force-assign analyst on every admin update; honor undefined vs null

analystId: input.analystId ?? ctx.auth.userId reassigns the analyst to the current admin on any update that omits analystId. It also prevents unassigning even if the client sends null (because ?? coalesces null). This will silently overwrite the responsible analyst during unrelated updates (status, scores, etc.).

Use tri-state semantics:

  • undefined: don't touch analystId
  • string: assign to that user
  • null: clear the assignment

Apply:

- analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual+ // Only modify when provided; allow null to clear+ ...(input.analystId !== undefined ? { analystId: input.analystId } : {}),

Optionally, if you want a one-time default assignment when there is no analyst yet, gate it explicitly:

// Before update, fetch current analystIdconstcurrent=awaitctx.db.suggestion.findUnique({where: {id: input.id},select: {analystId: true}});// In data:
...(input.analystId!==undefined
? {analystId: input.analystId}
: current?.analystId ? {} : {/* decide whether to set a default here or leave null */}),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 240, the current use of
"analystId: input.analystId ?? ctx.auth.userId" force-assigns the analyst on
every update and treats null as undefined; change this to tri-state handling:
fetch the current suggestion's analystId first, then when building the update
data only include analystId if input.analystId !== undefined (if string, set it;
if null, set it to null to clear), and do not fall back to ctx.auth.userId
implicitly — if you want a one-time default when there is no analyst, gate that
explicitly based on the fetched current value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rbxyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add user selection functionality for suggestions and update API… - #39

Merged
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões
Aug 26, 2025

Hidden character warning

The head ref may contain hidden characters: "34-adicionar-caixa-de-sugest\u00f5es"
Merged

feat: add user selection functionality for suggestions and update API…#39
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões

Conversation

@rbxyz

@rbxyzrbxyz commented Aug 26, 2025

Copy link
Copy Markdown
Collaborator

… to include analystId

Summary by CodeRabbit

  • New Features

    • Assign a responsible analyst to each suggestion using a user picker, with support for selecting or clearing (“Não atribuído”).
  • Improvements

    • Suggestions now consistently display the assigned analyst where applicable.
    • Clearer user identification in the picker (full name or email).
    • Minor UI refinements with improved dropdown indicators.

@vercel

vercelBot commented Aug 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
eloReadyReadyPreviewCommentAug 26, 2025 1:50pm

@coderabbitai

coderabbitaiBot commented Aug 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds analyst assignment support for suggestions: frontend introduces a UserSelector to set analystId per suggestion and threads _currentUser; backend expands admin list selection fields and updates admin update mutation to accept optional analystId, defaulting to the current user when not provided.

Changes

Cohort / File(s)Summary
Admin suggestions UI and data flow
src/app/(authenticated)/admin/suggestions/page.tsx
Adds analystId to local model; maps db analystId; introduces UserSelector (Popover + Command) to assign/clear analyst; wires update payload to include analystId; renames/passes _currentUser; replaces static responsible display with UserSelector; imports icons/components; minor console logging.
Suggestions API (admin endpoints)
src/server/api/routers/suggestions.ts
Admin list now uses select and returns expanded fields plus nested user/analyst; updateAdmin input adds optional analystId; update uses input.analystId or falls back to ctx.auth.userId; comment updated; non-admin flows unchanged.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Admin as Admin User
participant UI as AdminSuggestionsPage
participant Sel as UserSelector
participant API as tRPC: suggestions
participant DB as Database
Admin->>UI: Open admin suggestions
UI->>API: listAdmin()
API->>DB: SELECT id,...,analystId, user{...}, analyst{...}
DB-->>API: Rows
API-->>UI: Suggestions with analyst and user data
Admin->>Sel: Open analyst selector
Sel->>API: user.listAll()
API->>DB: SELECT users
DB-->>API: Users
API-->>Sel: Users list
Admin->>Sel: Choose analyst (or "Não atribuído")
Sel-->>UI: onValueChange(analystId|null)
UI->>API: updateAdmin({ id, ..., analystId? })
API->>DB: UPDATE suggestion SET analystId = input.analystId ?? ctx.auth.userId
DB-->>API: OK
API-->>UI: Updated suggestion
UI-->>Admin: Reflect updated responsible analyst
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers at the queue,
Assigning minds to ideas anew.
A hop, a click—analysts align,
The backend nods, selects refine.
With gentle thumps I mark the trail,
Suggestions sorted—cotton-tail. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 34-adicionar-caixa-de-sugestões

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/app/(authenticated)/admin/suggestions/page.tsx (1)

367-383: Preserve null for analystId; don’t coerce to undefined

Coercing null to undefined breaks unassigning semantics and, combined with the server’s current fallback, will reassign to the current admin. Keep null intact.

Apply:

- if (updates.analystId !== undefined) {- updateData.analystId = updates.analystId ?? undefined- }+ if (updates.analystId !== undefined) {+ // Keep null to explicitly clear assignment; undefined means no change+ updateData.analystId = updates.analystId+ }
🧹 Nitpick comments (6)
src/server/api/routers/suggestions.ts (1)

110-127: Good switch to explicit select; consider trimming unused fields to reduce payload

Nice move to an explicit select for admin list; this typically improves performance and keeps types tight. If the UI ultimately displays the user's sector (user.setor) instead of the submitted sector, consider dropping submittedSector from the selection to cut payload, or align the mapping to avoid confusion.

Example minimal trim:

 select: {
id: true,
ideaNumber: true,
submittedName: true,
- submittedSector: true,
isNameVisible: true,
description: true,
contribution: true,
dateRef: true,
impact: true,
capacity: true,
effort: true,
finalScore: true,
finalClassification: true,
status: true,
rejectionReason: true,
analystId: true,
createdAt: true,
user: {
select: {
firstName: true,
lastName: true,
email: true,
setor: true,
},
},
analyst: {
select: {
firstName: true,
lastName: true,
email: true,
},
},
},
src/app/(authenticated)/admin/suggestions/page.tsx (5)

44-45: Type captures the new responsibility concept; document tri-state intent

Defining analystId: string | null in SuggestionLocal is fine. For clarity and to align with the server change, ensure the app treats:

  • undefined: no change
  • string: assign to that user
  • null: unassign

Would you like me to sweep the components for places where analystId is constructed to ensure they adhere to this tri-state convention?


222-222: _currentUser is fetched but never used; avoid prop drilling

_currentUser is passed down multiple levels but not used. Either remove it to reduce churn, or leverage it (e.g., to show “Você” next to the current user in UserSelector).


612-612: Remove unused _currentUser prop passed through components

_currentUser is threaded through IdeasAccordion and SuggestionItem but unused. Trim these props to simplify component signatures and avoid unnecessary rerenders.

High-level diff outline:

- _currentUser={_currentUser}

And in component props:

- _currentUser: RouterOutputs["user"]["me"] | undefined

Also applies to: 630-630, 689-689, 701-701, 779-779, 806-806


1040-1044: Unassign flow and UX: ensure it works end-to-end and consider disabling while saving

This call path must allow setting analystId to null. With the client/server fixes above, the “Não atribuído” option will clear the assignment. Consider temporarily disabling the selector while the update mutation for this suggestion is in-flight to avoid rapid toggles causing racey UI.

Example (conceptual; needs plumbing of a per-suggestion pending state):

- <UserSelector+ <UserSelector
value={s.analystId}
- onValueChange={(userId: string | null) => {+ onValueChange={(userId: string | null) => {
update(s.id, { analystId: userId })
}}
- />+ disabled={/* pending state for this suggestion's update */}+ />

129-215: Ensure “Não atribuído” shows selected state, improve typing, scalability, and confirm security

Selected state
The “Não atribuído” item should display a checkmark when value === null, matching the behavior of other rows.

Typing
Update getUserDisplayName to use (typeof allUsers)[number] so the parameter type can never be undefined.

Scalability
Currently api.user.listAll.useQuery() fetches every user on mount. If the user count grows, consider switching to a server-side search or paginated endpoint to keep the popover performant.

Security
Verified that user.listAll is implemented with adminProcedure in src/server/api/routers/user.ts (lines 21–23), so only admins can call it.

Apply these optional refactors:

- const getUserDisplayName = (user: typeof allUsers[0]) => {+ const getUserDisplayName = (user: (typeof allUsers)[number]) => {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`
}
return user.email
}
 <CommandItem
onSelect={() => {
onValueChange(null)
setOpen(false)
}}
className="text-muted-foreground"
>
- <Check className="mr-2 h-4 w-4 opacity-0" />+ <Check className={`mr-2 h-4 w-4 ${value === null ? "opacity-100" : "opacity-0"}`} />
Não atribuído
</CommandItem>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0891924 and 1728631.

📒 Files selected for processing (2)
  • src/app/(authenticated)/admin/suggestions/page.tsx (15 hunks)
  • src/server/api/routers/suggestions.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/(authenticated)/admin/suggestions/page.tsx (4)
src/trpc/react.tsx (2)
  • api (23-23)
  • RouterOutputs (37-37)
src/components/ui/popover.tsx (3)
  • Popover (31-31)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/components/ui/command.tsx (6)
  • Command (144-144)
  • CommandInput (146-146)
  • CommandList (147-147)
  • CommandEmpty (148-148)
  • CommandGroup (149-149)
  • CommandItem (150-150)
🔇 Additional comments (5)
src/server/api/routers/suggestions.ts (1)

162-162: Comment update improves clarity

The updated doc comment calling out analyst handling is helpful for future readers.

src/app/(authenticated)/admin/suggestions/page.tsx (4)

18-18: Icon import looks good

Imports are consistent with usage in this file.


20-21: Command/Popover UI imports are appropriate

Matches the new UserSelector implementation below.


113-113: Mapping analystId from DB is correct

Direct pass-through matches the server select.


313-338: Classification pools: good memoized mapping

Mapping tRPC results to local ClassItem[] is straightforward and readable.

kpis: z.array(z.string()).optional(),
status: StatusEnum.optional(),
rejectionReason: z.string().optional(),
analystId: z.string().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow null to enable unassigning an analyst (tri-state: string | null | undefined)

Right now analystId is z.string().optional(). That makes it impossible to intentionally clear the responsible analyst: sending null fails validation; omitting the field (undefined) currently triggers a fallback (see Line 240) that will force-assign the current admin. Support null so the client can unassign.

Apply:

- analystId: z.string().optional(),+ // string = assign to user; null = unassign; undefined = do not change+ analystId: z.string().nullable().optional(),
📝 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.

Suggested change
analystId: z.string().optional(),
// string = assign to user; null = unassign; undefined = do not change
analystId: z.string().nullable().optional(),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 172, the Zod schema for
analystId should accept null so clients can explicitly unassign; change the
schema to allow string | null | undefined (e.g., make it nullable and optional).
Also adjust the handling around line 240 so the "fallback to current admin" only
runs when analystId is strictly undefined (preserve existing behavior for
omitted field) and treat a null value as an explicit unassign (do not replace it
with the current admin).

status: input.status,
rejectionReason: input.rejectionReason,
analystId: ctx.auth.userId,
analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not force-assign analyst on every admin update; honor undefined vs null

analystId: input.analystId ?? ctx.auth.userId reassigns the analyst to the current admin on any update that omits analystId. It also prevents unassigning even if the client sends null (because ?? coalesces null). This will silently overwrite the responsible analyst during unrelated updates (status, scores, etc.).

Use tri-state semantics:

  • undefined: don't touch analystId
  • string: assign to that user
  • null: clear the assignment

Apply:

- analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual+ // Only modify when provided; allow null to clear+ ...(input.analystId !== undefined ? { analystId: input.analystId } : {}),

Optionally, if you want a one-time default assignment when there is no analyst yet, gate it explicitly:

// Before update, fetch current analystIdconstcurrent=awaitctx.db.suggestion.findUnique({where: {id: input.id},select: {analystId: true}});// In data:
...(input.analystId!==undefined
? {analystId: input.analystId}
: current?.analystId ? {} : {/* decide whether to set a default here or leave null */}),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 240, the current use of
"analystId: input.analystId ?? ctx.auth.userId" force-assigns the analyst on
every update and treats null as undefined; change this to tri-state handling:
fetch the current suggestion's analystId first, then when building the update
data only include analystId if input.analystId !== undefined (if string, set it;
if null, set it to null to clear), and do not fall back to ctx.auth.userId
implicitly — if you want a one-time default when there is no analyst, gate that
explicitly based on the fetched current value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rbxyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: add user selection functionality for suggestions and update API… - #39

Merged
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões
Aug 26, 2025

Hidden character warning

The head ref may contain hidden characters: "34-adicionar-caixa-de-sugest\u00f5es"
Merged

feat: add user selection functionality for suggestions and update API…#39
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões

Conversation

@rbxyz

@rbxyzrbxyz commented Aug 26, 2025

Copy link
Copy Markdown
Collaborator

… to include analystId

Summary by CodeRabbit

  • New Features

    • Assign a responsible analyst to each suggestion using a user picker, with support for selecting or clearing (“Não atribuído”).
  • Improvements

    • Suggestions now consistently display the assigned analyst where applicable.
    • Clearer user identification in the picker (full name or email).
    • Minor UI refinements with improved dropdown indicators.

@vercel

vercelBot commented Aug 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
eloReadyReadyPreviewCommentAug 26, 2025 1:50pm

@coderabbitai

coderabbitaiBot commented Aug 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds analyst assignment support for suggestions: frontend introduces a UserSelector to set analystId per suggestion and threads _currentUser; backend expands admin list selection fields and updates admin update mutation to accept optional analystId, defaulting to the current user when not provided.

Changes

Cohort / File(s)Summary
Admin suggestions UI and data flow
src/app/(authenticated)/admin/suggestions/page.tsx
Adds analystId to local model; maps db analystId; introduces UserSelector (Popover + Command) to assign/clear analyst; wires update payload to include analystId; renames/passes _currentUser; replaces static responsible display with UserSelector; imports icons/components; minor console logging.
Suggestions API (admin endpoints)
src/server/api/routers/suggestions.ts
Admin list now uses select and returns expanded fields plus nested user/analyst; updateAdmin input adds optional analystId; update uses input.analystId or falls back to ctx.auth.userId; comment updated; non-admin flows unchanged.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Admin as Admin User
participant UI as AdminSuggestionsPage
participant Sel as UserSelector
participant API as tRPC: suggestions
participant DB as Database
Admin->>UI: Open admin suggestions
UI->>API: listAdmin()
API->>DB: SELECT id,...,analystId, user{...}, analyst{...}
DB-->>API: Rows
API-->>UI: Suggestions with analyst and user data
Admin->>Sel: Open analyst selector
Sel->>API: user.listAll()
API->>DB: SELECT users
DB-->>API: Users
API-->>Sel: Users list
Admin->>Sel: Choose analyst (or "Não atribuído")
Sel-->>UI: onValueChange(analystId|null)
UI->>API: updateAdmin({ id, ..., analystId? })
API->>DB: UPDATE suggestion SET analystId = input.analystId ?? ctx.auth.userId
DB-->>API: OK
API-->>UI: Updated suggestion
UI-->>Admin: Reflect updated responsible analyst
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers at the queue,
Assigning minds to ideas anew.
A hop, a click—analysts align,
The backend nods, selects refine.
With gentle thumps I mark the trail,
Suggestions sorted—cotton-tail. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 34-adicionar-caixa-de-sugestões

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/app/(authenticated)/admin/suggestions/page.tsx (1)

367-383: Preserve null for analystId; don’t coerce to undefined

Coercing null to undefined breaks unassigning semantics and, combined with the server’s current fallback, will reassign to the current admin. Keep null intact.

Apply:

- if (updates.analystId !== undefined) {- updateData.analystId = updates.analystId ?? undefined- }+ if (updates.analystId !== undefined) {+ // Keep null to explicitly clear assignment; undefined means no change+ updateData.analystId = updates.analystId+ }
🧹 Nitpick comments (6)
src/server/api/routers/suggestions.ts (1)

110-127: Good switch to explicit select; consider trimming unused fields to reduce payload

Nice move to an explicit select for admin list; this typically improves performance and keeps types tight. If the UI ultimately displays the user's sector (user.setor) instead of the submitted sector, consider dropping submittedSector from the selection to cut payload, or align the mapping to avoid confusion.

Example minimal trim:

 select: {
id: true,
ideaNumber: true,
submittedName: true,
- submittedSector: true,
isNameVisible: true,
description: true,
contribution: true,
dateRef: true,
impact: true,
capacity: true,
effort: true,
finalScore: true,
finalClassification: true,
status: true,
rejectionReason: true,
analystId: true,
createdAt: true,
user: {
select: {
firstName: true,
lastName: true,
email: true,
setor: true,
},
},
analyst: {
select: {
firstName: true,
lastName: true,
email: true,
},
},
},
src/app/(authenticated)/admin/suggestions/page.tsx (5)

44-45: Type captures the new responsibility concept; document tri-state intent

Defining analystId: string | null in SuggestionLocal is fine. For clarity and to align with the server change, ensure the app treats:

  • undefined: no change
  • string: assign to that user
  • null: unassign

Would you like me to sweep the components for places where analystId is constructed to ensure they adhere to this tri-state convention?


222-222: _currentUser is fetched but never used; avoid prop drilling

_currentUser is passed down multiple levels but not used. Either remove it to reduce churn, or leverage it (e.g., to show “Você” next to the current user in UserSelector).


612-612: Remove unused _currentUser prop passed through components

_currentUser is threaded through IdeasAccordion and SuggestionItem but unused. Trim these props to simplify component signatures and avoid unnecessary rerenders.

High-level diff outline:

- _currentUser={_currentUser}

And in component props:

- _currentUser: RouterOutputs["user"]["me"] | undefined

Also applies to: 630-630, 689-689, 701-701, 779-779, 806-806


1040-1044: Unassign flow and UX: ensure it works end-to-end and consider disabling while saving

This call path must allow setting analystId to null. With the client/server fixes above, the “Não atribuído” option will clear the assignment. Consider temporarily disabling the selector while the update mutation for this suggestion is in-flight to avoid rapid toggles causing racey UI.

Example (conceptual; needs plumbing of a per-suggestion pending state):

- <UserSelector+ <UserSelector
value={s.analystId}
- onValueChange={(userId: string | null) => {+ onValueChange={(userId: string | null) => {
update(s.id, { analystId: userId })
}}
- />+ disabled={/* pending state for this suggestion's update */}+ />

129-215: Ensure “Não atribuído” shows selected state, improve typing, scalability, and confirm security

Selected state
The “Não atribuído” item should display a checkmark when value === null, matching the behavior of other rows.

Typing
Update getUserDisplayName to use (typeof allUsers)[number] so the parameter type can never be undefined.

Scalability
Currently api.user.listAll.useQuery() fetches every user on mount. If the user count grows, consider switching to a server-side search or paginated endpoint to keep the popover performant.

Security
Verified that user.listAll is implemented with adminProcedure in src/server/api/routers/user.ts (lines 21–23), so only admins can call it.

Apply these optional refactors:

- const getUserDisplayName = (user: typeof allUsers[0]) => {+ const getUserDisplayName = (user: (typeof allUsers)[number]) => {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`
}
return user.email
}
 <CommandItem
onSelect={() => {
onValueChange(null)
setOpen(false)
}}
className="text-muted-foreground"
>
- <Check className="mr-2 h-4 w-4 opacity-0" />+ <Check className={`mr-2 h-4 w-4 ${value === null ? "opacity-100" : "opacity-0"}`} />
Não atribuído
</CommandItem>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0891924 and 1728631.

📒 Files selected for processing (2)
  • src/app/(authenticated)/admin/suggestions/page.tsx (15 hunks)
  • src/server/api/routers/suggestions.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/(authenticated)/admin/suggestions/page.tsx (4)
src/trpc/react.tsx (2)
  • api (23-23)
  • RouterOutputs (37-37)
src/components/ui/popover.tsx (3)
  • Popover (31-31)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/components/ui/command.tsx (6)
  • Command (144-144)
  • CommandInput (146-146)
  • CommandList (147-147)
  • CommandEmpty (148-148)
  • CommandGroup (149-149)
  • CommandItem (150-150)
🔇 Additional comments (5)
src/server/api/routers/suggestions.ts (1)

162-162: Comment update improves clarity

The updated doc comment calling out analyst handling is helpful for future readers.

src/app/(authenticated)/admin/suggestions/page.tsx (4)

18-18: Icon import looks good

Imports are consistent with usage in this file.


20-21: Command/Popover UI imports are appropriate

Matches the new UserSelector implementation below.


113-113: Mapping analystId from DB is correct

Direct pass-through matches the server select.


313-338: Classification pools: good memoized mapping

Mapping tRPC results to local ClassItem[] is straightforward and readable.

kpis: z.array(z.string()).optional(),
status: StatusEnum.optional(),
rejectionReason: z.string().optional(),
analystId: z.string().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow null to enable unassigning an analyst (tri-state: string | null | undefined)

Right now analystId is z.string().optional(). That makes it impossible to intentionally clear the responsible analyst: sending null fails validation; omitting the field (undefined) currently triggers a fallback (see Line 240) that will force-assign the current admin. Support null so the client can unassign.

Apply:

- analystId: z.string().optional(),+ // string = assign to user; null = unassign; undefined = do not change+ analystId: z.string().nullable().optional(),
📝 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.

Suggested change
analystId: z.string().optional(),
// string = assign to user; null = unassign; undefined = do not change
analystId: z.string().nullable().optional(),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 172, the Zod schema for
analystId should accept null so clients can explicitly unassign; change the
schema to allow string | null | undefined (e.g., make it nullable and optional).
Also adjust the handling around line 240 so the "fallback to current admin" only
runs when analystId is strictly undefined (preserve existing behavior for
omitted field) and treat a null value as an explicit unassign (do not replace it
with the current admin).

status: input.status,
rejectionReason: input.rejectionReason,
analystId: ctx.auth.userId,
analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not force-assign analyst on every admin update; honor undefined vs null

analystId: input.analystId ?? ctx.auth.userId reassigns the analyst to the current admin on any update that omits analystId. It also prevents unassigning even if the client sends null (because ?? coalesces null). This will silently overwrite the responsible analyst during unrelated updates (status, scores, etc.).

Use tri-state semantics:

  • undefined: don't touch analystId
  • string: assign to that user
  • null: clear the assignment

Apply:

- analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual+ // Only modify when provided; allow null to clear+ ...(input.analystId !== undefined ? { analystId: input.analystId } : {}),

Optionally, if you want a one-time default assignment when there is no analyst yet, gate it explicitly:

// Before update, fetch current analystIdconstcurrent=awaitctx.db.suggestion.findUnique({where: {id: input.id},select: {analystId: true}});// In data:
...(input.analystId!==undefined
? {analystId: input.analystId}
: current?.analystId ? {} : {/* decide whether to set a default here or leave null */}),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 240, the current use of
"analystId: input.analystId ?? ctx.auth.userId" force-assigns the analyst on
every update and treats null as undefined; change this to tri-state handling:
fetch the current suggestion's analystId first, then when building the update
data only include analystId if input.analystId !== undefined (if string, set it;
if null, set it to null to clear), and do not fall back to ctx.auth.userId
implicitly — if you want a one-time default when there is no analyst, gate that
explicitly based on the fetched current value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rbxyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add user selection functionality for suggestions and update API… - #39

Merged
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões
Aug 26, 2025

Hidden character warning

The head ref may contain hidden characters: "34-adicionar-caixa-de-sugest\u00f5es"
Merged

feat: add user selection functionality for suggestions and update API…#39
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões

Conversation

@rbxyz

@rbxyzrbxyz commented Aug 26, 2025

Copy link
Copy Markdown
Collaborator

… to include analystId

Summary by CodeRabbit

  • New Features

    • Assign a responsible analyst to each suggestion using a user picker, with support for selecting or clearing (“Não atribuído”).
  • Improvements

    • Suggestions now consistently display the assigned analyst where applicable.
    • Clearer user identification in the picker (full name or email).
    • Minor UI refinements with improved dropdown indicators.

@vercel

vercelBot commented Aug 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
eloReadyReadyPreviewCommentAug 26, 2025 1:50pm

@coderabbitai

coderabbitaiBot commented Aug 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds analyst assignment support for suggestions: frontend introduces a UserSelector to set analystId per suggestion and threads _currentUser; backend expands admin list selection fields and updates admin update mutation to accept optional analystId, defaulting to the current user when not provided.

Changes

Cohort / File(s)Summary
Admin suggestions UI and data flow
src/app/(authenticated)/admin/suggestions/page.tsx
Adds analystId to local model; maps db analystId; introduces UserSelector (Popover + Command) to assign/clear analyst; wires update payload to include analystId; renames/passes _currentUser; replaces static responsible display with UserSelector; imports icons/components; minor console logging.
Suggestions API (admin endpoints)
src/server/api/routers/suggestions.ts
Admin list now uses select and returns expanded fields plus nested user/analyst; updateAdmin input adds optional analystId; update uses input.analystId or falls back to ctx.auth.userId; comment updated; non-admin flows unchanged.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Admin as Admin User
participant UI as AdminSuggestionsPage
participant Sel as UserSelector
participant API as tRPC: suggestions
participant DB as Database
Admin->>UI: Open admin suggestions
UI->>API: listAdmin()
API->>DB: SELECT id,...,analystId, user{...}, analyst{...}
DB-->>API: Rows
API-->>UI: Suggestions with analyst and user data
Admin->>Sel: Open analyst selector
Sel->>API: user.listAll()
API->>DB: SELECT users
DB-->>API: Users
API-->>Sel: Users list
Admin->>Sel: Choose analyst (or "Não atribuído")
Sel-->>UI: onValueChange(analystId|null)
UI->>API: updateAdmin({ id, ..., analystId? })
API->>DB: UPDATE suggestion SET analystId = input.analystId ?? ctx.auth.userId
DB-->>API: OK
API-->>UI: Updated suggestion
UI-->>Admin: Reflect updated responsible analyst
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers at the queue,
Assigning minds to ideas anew.
A hop, a click—analysts align,
The backend nods, selects refine.
With gentle thumps I mark the trail,
Suggestions sorted—cotton-tail. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 34-adicionar-caixa-de-sugestões

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/app/(authenticated)/admin/suggestions/page.tsx (1)

367-383: Preserve null for analystId; don’t coerce to undefined

Coercing null to undefined breaks unassigning semantics and, combined with the server’s current fallback, will reassign to the current admin. Keep null intact.

Apply:

- if (updates.analystId !== undefined) {- updateData.analystId = updates.analystId ?? undefined- }+ if (updates.analystId !== undefined) {+ // Keep null to explicitly clear assignment; undefined means no change+ updateData.analystId = updates.analystId+ }
🧹 Nitpick comments (6)
src/server/api/routers/suggestions.ts (1)

110-127: Good switch to explicit select; consider trimming unused fields to reduce payload

Nice move to an explicit select for admin list; this typically improves performance and keeps types tight. If the UI ultimately displays the user's sector (user.setor) instead of the submitted sector, consider dropping submittedSector from the selection to cut payload, or align the mapping to avoid confusion.

Example minimal trim:

 select: {
id: true,
ideaNumber: true,
submittedName: true,
- submittedSector: true,
isNameVisible: true,
description: true,
contribution: true,
dateRef: true,
impact: true,
capacity: true,
effort: true,
finalScore: true,
finalClassification: true,
status: true,
rejectionReason: true,
analystId: true,
createdAt: true,
user: {
select: {
firstName: true,
lastName: true,
email: true,
setor: true,
},
},
analyst: {
select: {
firstName: true,
lastName: true,
email: true,
},
},
},
src/app/(authenticated)/admin/suggestions/page.tsx (5)

44-45: Type captures the new responsibility concept; document tri-state intent

Defining analystId: string | null in SuggestionLocal is fine. For clarity and to align with the server change, ensure the app treats:

  • undefined: no change
  • string: assign to that user
  • null: unassign

Would you like me to sweep the components for places where analystId is constructed to ensure they adhere to this tri-state convention?


222-222: _currentUser is fetched but never used; avoid prop drilling

_currentUser is passed down multiple levels but not used. Either remove it to reduce churn, or leverage it (e.g., to show “Você” next to the current user in UserSelector).


612-612: Remove unused _currentUser prop passed through components

_currentUser is threaded through IdeasAccordion and SuggestionItem but unused. Trim these props to simplify component signatures and avoid unnecessary rerenders.

High-level diff outline:

- _currentUser={_currentUser}

And in component props:

- _currentUser: RouterOutputs["user"]["me"] | undefined

Also applies to: 630-630, 689-689, 701-701, 779-779, 806-806


1040-1044: Unassign flow and UX: ensure it works end-to-end and consider disabling while saving

This call path must allow setting analystId to null. With the client/server fixes above, the “Não atribuído” option will clear the assignment. Consider temporarily disabling the selector while the update mutation for this suggestion is in-flight to avoid rapid toggles causing racey UI.

Example (conceptual; needs plumbing of a per-suggestion pending state):

- <UserSelector+ <UserSelector
value={s.analystId}
- onValueChange={(userId: string | null) => {+ onValueChange={(userId: string | null) => {
update(s.id, { analystId: userId })
}}
- />+ disabled={/* pending state for this suggestion's update */}+ />

129-215: Ensure “Não atribuído” shows selected state, improve typing, scalability, and confirm security

Selected state
The “Não atribuído” item should display a checkmark when value === null, matching the behavior of other rows.

Typing
Update getUserDisplayName to use (typeof allUsers)[number] so the parameter type can never be undefined.

Scalability
Currently api.user.listAll.useQuery() fetches every user on mount. If the user count grows, consider switching to a server-side search or paginated endpoint to keep the popover performant.

Security
Verified that user.listAll is implemented with adminProcedure in src/server/api/routers/user.ts (lines 21–23), so only admins can call it.

Apply these optional refactors:

- const getUserDisplayName = (user: typeof allUsers[0]) => {+ const getUserDisplayName = (user: (typeof allUsers)[number]) => {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`
}
return user.email
}
 <CommandItem
onSelect={() => {
onValueChange(null)
setOpen(false)
}}
className="text-muted-foreground"
>
- <Check className="mr-2 h-4 w-4 opacity-0" />+ <Check className={`mr-2 h-4 w-4 ${value === null ? "opacity-100" : "opacity-0"}`} />
Não atribuído
</CommandItem>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0891924 and 1728631.

📒 Files selected for processing (2)
  • src/app/(authenticated)/admin/suggestions/page.tsx (15 hunks)
  • src/server/api/routers/suggestions.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/(authenticated)/admin/suggestions/page.tsx (4)
src/trpc/react.tsx (2)
  • api (23-23)
  • RouterOutputs (37-37)
src/components/ui/popover.tsx (3)
  • Popover (31-31)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/components/ui/command.tsx (6)
  • Command (144-144)
  • CommandInput (146-146)
  • CommandList (147-147)
  • CommandEmpty (148-148)
  • CommandGroup (149-149)
  • CommandItem (150-150)
🔇 Additional comments (5)
src/server/api/routers/suggestions.ts (1)

162-162: Comment update improves clarity

The updated doc comment calling out analyst handling is helpful for future readers.

src/app/(authenticated)/admin/suggestions/page.tsx (4)

18-18: Icon import looks good

Imports are consistent with usage in this file.


20-21: Command/Popover UI imports are appropriate

Matches the new UserSelector implementation below.


113-113: Mapping analystId from DB is correct

Direct pass-through matches the server select.


313-338: Classification pools: good memoized mapping

Mapping tRPC results to local ClassItem[] is straightforward and readable.

kpis: z.array(z.string()).optional(),
status: StatusEnum.optional(),
rejectionReason: z.string().optional(),
analystId: z.string().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow null to enable unassigning an analyst (tri-state: string | null | undefined)

Right now analystId is z.string().optional(). That makes it impossible to intentionally clear the responsible analyst: sending null fails validation; omitting the field (undefined) currently triggers a fallback (see Line 240) that will force-assign the current admin. Support null so the client can unassign.

Apply:

- analystId: z.string().optional(),+ // string = assign to user; null = unassign; undefined = do not change+ analystId: z.string().nullable().optional(),
📝 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.

Suggested change
analystId: z.string().optional(),
// string = assign to user; null = unassign; undefined = do not change
analystId: z.string().nullable().optional(),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 172, the Zod schema for
analystId should accept null so clients can explicitly unassign; change the
schema to allow string | null | undefined (e.g., make it nullable and optional).
Also adjust the handling around line 240 so the "fallback to current admin" only
runs when analystId is strictly undefined (preserve existing behavior for
omitted field) and treat a null value as an explicit unassign (do not replace it
with the current admin).

status: input.status,
rejectionReason: input.rejectionReason,
analystId: ctx.auth.userId,
analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not force-assign analyst on every admin update; honor undefined vs null

analystId: input.analystId ?? ctx.auth.userId reassigns the analyst to the current admin on any update that omits analystId. It also prevents unassigning even if the client sends null (because ?? coalesces null). This will silently overwrite the responsible analyst during unrelated updates (status, scores, etc.).

Use tri-state semantics:

  • undefined: don't touch analystId
  • string: assign to that user
  • null: clear the assignment

Apply:

- analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual+ // Only modify when provided; allow null to clear+ ...(input.analystId !== undefined ? { analystId: input.analystId } : {}),

Optionally, if you want a one-time default assignment when there is no analyst yet, gate it explicitly:

// Before update, fetch current analystIdconstcurrent=awaitctx.db.suggestion.findUnique({where: {id: input.id},select: {analystId: true}});// In data:
...(input.analystId!==undefined
? {analystId: input.analystId}
: current?.analystId ? {} : {/* decide whether to set a default here or leave null */}),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 240, the current use of
"analystId: input.analystId ?? ctx.auth.userId" force-assigns the analyst on
every update and treats null as undefined; change this to tri-state handling:
fetch the current suggestion's analystId first, then when building the update
data only include analystId if input.analystId !== undefined (if string, set it;
if null, set it to null to clear), and do not fall back to ctx.auth.userId
implicitly — if you want a one-time default when there is no analyst, gate that
explicitly based on the fetched current value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rbxyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add user selection functionality for suggestions and update API… - #39

Merged
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões
Aug 26, 2025

Hidden character warning

The head ref may contain hidden characters: "34-adicionar-caixa-de-sugest\u00f5es"
Merged

feat: add user selection functionality for suggestions and update API…#39
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões

Conversation

@rbxyz

@rbxyzrbxyz commented Aug 26, 2025

Copy link
Copy Markdown
Collaborator

… to include analystId

Summary by CodeRabbit

  • New Features

    • Assign a responsible analyst to each suggestion using a user picker, with support for selecting or clearing (“Não atribuído”).
  • Improvements

    • Suggestions now consistently display the assigned analyst where applicable.
    • Clearer user identification in the picker (full name or email).
    • Minor UI refinements with improved dropdown indicators.

@vercel

vercelBot commented Aug 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
eloReadyReadyPreviewCommentAug 26, 2025 1:50pm

@coderabbitai

coderabbitaiBot commented Aug 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds analyst assignment support for suggestions: frontend introduces a UserSelector to set analystId per suggestion and threads _currentUser; backend expands admin list selection fields and updates admin update mutation to accept optional analystId, defaulting to the current user when not provided.

Changes

Cohort / File(s)Summary
Admin suggestions UI and data flow
src/app/(authenticated)/admin/suggestions/page.tsx
Adds analystId to local model; maps db analystId; introduces UserSelector (Popover + Command) to assign/clear analyst; wires update payload to include analystId; renames/passes _currentUser; replaces static responsible display with UserSelector; imports icons/components; minor console logging.
Suggestions API (admin endpoints)
src/server/api/routers/suggestions.ts
Admin list now uses select and returns expanded fields plus nested user/analyst; updateAdmin input adds optional analystId; update uses input.analystId or falls back to ctx.auth.userId; comment updated; non-admin flows unchanged.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Admin as Admin User
participant UI as AdminSuggestionsPage
participant Sel as UserSelector
participant API as tRPC: suggestions
participant DB as Database
Admin->>UI: Open admin suggestions
UI->>API: listAdmin()
API->>DB: SELECT id,...,analystId, user{...}, analyst{...}
DB-->>API: Rows
API-->>UI: Suggestions with analyst and user data
Admin->>Sel: Open analyst selector
Sel->>API: user.listAll()
API->>DB: SELECT users
DB-->>API: Users
API-->>Sel: Users list
Admin->>Sel: Choose analyst (or "Não atribuído")
Sel-->>UI: onValueChange(analystId|null)
UI->>API: updateAdmin({ id, ..., analystId? })
API->>DB: UPDATE suggestion SET analystId = input.analystId ?? ctx.auth.userId
DB-->>API: OK
API-->>UI: Updated suggestion
UI-->>Admin: Reflect updated responsible analyst
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers at the queue,
Assigning minds to ideas anew.
A hop, a click—analysts align,
The backend nods, selects refine.
With gentle thumps I mark the trail,
Suggestions sorted—cotton-tail. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 34-adicionar-caixa-de-sugestões

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/app/(authenticated)/admin/suggestions/page.tsx (1)

367-383: Preserve null for analystId; don’t coerce to undefined

Coercing null to undefined breaks unassigning semantics and, combined with the server’s current fallback, will reassign to the current admin. Keep null intact.

Apply:

- if (updates.analystId !== undefined) {- updateData.analystId = updates.analystId ?? undefined- }+ if (updates.analystId !== undefined) {+ // Keep null to explicitly clear assignment; undefined means no change+ updateData.analystId = updates.analystId+ }
🧹 Nitpick comments (6)
src/server/api/routers/suggestions.ts (1)

110-127: Good switch to explicit select; consider trimming unused fields to reduce payload

Nice move to an explicit select for admin list; this typically improves performance and keeps types tight. If the UI ultimately displays the user's sector (user.setor) instead of the submitted sector, consider dropping submittedSector from the selection to cut payload, or align the mapping to avoid confusion.

Example minimal trim:

 select: {
id: true,
ideaNumber: true,
submittedName: true,
- submittedSector: true,
isNameVisible: true,
description: true,
contribution: true,
dateRef: true,
impact: true,
capacity: true,
effort: true,
finalScore: true,
finalClassification: true,
status: true,
rejectionReason: true,
analystId: true,
createdAt: true,
user: {
select: {
firstName: true,
lastName: true,
email: true,
setor: true,
},
},
analyst: {
select: {
firstName: true,
lastName: true,
email: true,
},
},
},
src/app/(authenticated)/admin/suggestions/page.tsx (5)

44-45: Type captures the new responsibility concept; document tri-state intent

Defining analystId: string | null in SuggestionLocal is fine. For clarity and to align with the server change, ensure the app treats:

  • undefined: no change
  • string: assign to that user
  • null: unassign

Would you like me to sweep the components for places where analystId is constructed to ensure they adhere to this tri-state convention?


222-222: _currentUser is fetched but never used; avoid prop drilling

_currentUser is passed down multiple levels but not used. Either remove it to reduce churn, or leverage it (e.g., to show “Você” next to the current user in UserSelector).


612-612: Remove unused _currentUser prop passed through components

_currentUser is threaded through IdeasAccordion and SuggestionItem but unused. Trim these props to simplify component signatures and avoid unnecessary rerenders.

High-level diff outline:

- _currentUser={_currentUser}

And in component props:

- _currentUser: RouterOutputs["user"]["me"] | undefined

Also applies to: 630-630, 689-689, 701-701, 779-779, 806-806


1040-1044: Unassign flow and UX: ensure it works end-to-end and consider disabling while saving

This call path must allow setting analystId to null. With the client/server fixes above, the “Não atribuído” option will clear the assignment. Consider temporarily disabling the selector while the update mutation for this suggestion is in-flight to avoid rapid toggles causing racey UI.

Example (conceptual; needs plumbing of a per-suggestion pending state):

- <UserSelector+ <UserSelector
value={s.analystId}
- onValueChange={(userId: string | null) => {+ onValueChange={(userId: string | null) => {
update(s.id, { analystId: userId })
}}
- />+ disabled={/* pending state for this suggestion's update */}+ />

129-215: Ensure “Não atribuído” shows selected state, improve typing, scalability, and confirm security

Selected state
The “Não atribuído” item should display a checkmark when value === null, matching the behavior of other rows.

Typing
Update getUserDisplayName to use (typeof allUsers)[number] so the parameter type can never be undefined.

Scalability
Currently api.user.listAll.useQuery() fetches every user on mount. If the user count grows, consider switching to a server-side search or paginated endpoint to keep the popover performant.

Security
Verified that user.listAll is implemented with adminProcedure in src/server/api/routers/user.ts (lines 21–23), so only admins can call it.

Apply these optional refactors:

- const getUserDisplayName = (user: typeof allUsers[0]) => {+ const getUserDisplayName = (user: (typeof allUsers)[number]) => {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`
}
return user.email
}
 <CommandItem
onSelect={() => {
onValueChange(null)
setOpen(false)
}}
className="text-muted-foreground"
>
- <Check className="mr-2 h-4 w-4 opacity-0" />+ <Check className={`mr-2 h-4 w-4 ${value === null ? "opacity-100" : "opacity-0"}`} />
Não atribuído
</CommandItem>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0891924 and 1728631.

📒 Files selected for processing (2)
  • src/app/(authenticated)/admin/suggestions/page.tsx (15 hunks)
  • src/server/api/routers/suggestions.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/(authenticated)/admin/suggestions/page.tsx (4)
src/trpc/react.tsx (2)
  • api (23-23)
  • RouterOutputs (37-37)
src/components/ui/popover.tsx (3)
  • Popover (31-31)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/components/ui/command.tsx (6)
  • Command (144-144)
  • CommandInput (146-146)
  • CommandList (147-147)
  • CommandEmpty (148-148)
  • CommandGroup (149-149)
  • CommandItem (150-150)
🔇 Additional comments (5)
src/server/api/routers/suggestions.ts (1)

162-162: Comment update improves clarity

The updated doc comment calling out analyst handling is helpful for future readers.

src/app/(authenticated)/admin/suggestions/page.tsx (4)

18-18: Icon import looks good

Imports are consistent with usage in this file.


20-21: Command/Popover UI imports are appropriate

Matches the new UserSelector implementation below.


113-113: Mapping analystId from DB is correct

Direct pass-through matches the server select.


313-338: Classification pools: good memoized mapping

Mapping tRPC results to local ClassItem[] is straightforward and readable.

kpis: z.array(z.string()).optional(),
status: StatusEnum.optional(),
rejectionReason: z.string().optional(),
analystId: z.string().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow null to enable unassigning an analyst (tri-state: string | null | undefined)

Right now analystId is z.string().optional(). That makes it impossible to intentionally clear the responsible analyst: sending null fails validation; omitting the field (undefined) currently triggers a fallback (see Line 240) that will force-assign the current admin. Support null so the client can unassign.

Apply:

- analystId: z.string().optional(),+ // string = assign to user; null = unassign; undefined = do not change+ analystId: z.string().nullable().optional(),
📝 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.

Suggested change
analystId: z.string().optional(),
// string = assign to user; null = unassign; undefined = do not change
analystId: z.string().nullable().optional(),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 172, the Zod schema for
analystId should accept null so clients can explicitly unassign; change the
schema to allow string | null | undefined (e.g., make it nullable and optional).
Also adjust the handling around line 240 so the "fallback to current admin" only
runs when analystId is strictly undefined (preserve existing behavior for
omitted field) and treat a null value as an explicit unassign (do not replace it
with the current admin).

status: input.status,
rejectionReason: input.rejectionReason,
analystId: ctx.auth.userId,
analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not force-assign analyst on every admin update; honor undefined vs null

analystId: input.analystId ?? ctx.auth.userId reassigns the analyst to the current admin on any update that omits analystId. It also prevents unassigning even if the client sends null (because ?? coalesces null). This will silently overwrite the responsible analyst during unrelated updates (status, scores, etc.).

Use tri-state semantics:

  • undefined: don't touch analystId
  • string: assign to that user
  • null: clear the assignment

Apply:

- analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual+ // Only modify when provided; allow null to clear+ ...(input.analystId !== undefined ? { analystId: input.analystId } : {}),

Optionally, if you want a one-time default assignment when there is no analyst yet, gate it explicitly:

// Before update, fetch current analystIdconstcurrent=awaitctx.db.suggestion.findUnique({where: {id: input.id},select: {analystId: true}});// In data:
...(input.analystId!==undefined
? {analystId: input.analystId}
: current?.analystId ? {} : {/* decide whether to set a default here or leave null */}),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 240, the current use of
"analystId: input.analystId ?? ctx.auth.userId" force-assigns the analyst on
every update and treats null as undefined; change this to tri-state handling:
fetch the current suggestion's analystId first, then when building the update
data only include analystId if input.analystId !== undefined (if string, set it;
if null, set it to null to clear), and do not fall back to ctx.auth.userId
implicitly — if you want a one-time default when there is no analyst, gate that
explicitly based on the fetched current value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rbxyz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: add user selection functionality for suggestions and update API… - #39

Merged
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões
Aug 26, 2025

Hidden character warning

The head ref may contain hidden characters: "34-adicionar-caixa-de-sugest\u00f5es"
Merged

feat: add user selection functionality for suggestions and update API…#39
rbxyz merged 1 commit into
mainfrom
34-adicionar-caixa-de-sugestões

Conversation

@rbxyz

@rbxyzrbxyz commented Aug 26, 2025

Copy link
Copy Markdown
Collaborator

… to include analystId

Summary by CodeRabbit

  • New Features

    • Assign a responsible analyst to each suggestion using a user picker, with support for selecting or clearing (“Não atribuído”).
  • Improvements

    • Suggestions now consistently display the assigned analyst where applicable.
    • Clearer user identification in the picker (full name or email).
    • Minor UI refinements with improved dropdown indicators.

@vercel

vercelBot commented Aug 26, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentPreviewCommentsUpdated (UTC)
eloReadyReadyPreviewCommentAug 26, 2025 1:50pm

@coderabbitai

coderabbitaiBot commented Aug 26, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds analyst assignment support for suggestions: frontend introduces a UserSelector to set analystId per suggestion and threads _currentUser; backend expands admin list selection fields and updates admin update mutation to accept optional analystId, defaulting to the current user when not provided.

Changes

Cohort / File(s)Summary
Admin suggestions UI and data flow
src/app/(authenticated)/admin/suggestions/page.tsx
Adds analystId to local model; maps db analystId; introduces UserSelector (Popover + Command) to assign/clear analyst; wires update payload to include analystId; renames/passes _currentUser; replaces static responsible display with UserSelector; imports icons/components; minor console logging.
Suggestions API (admin endpoints)
src/server/api/routers/suggestions.ts
Admin list now uses select and returns expanded fields plus nested user/analyst; updateAdmin input adds optional analystId; update uses input.analystId or falls back to ctx.auth.userId; comment updated; non-admin flows unchanged.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Admin as Admin User
participant UI as AdminSuggestionsPage
participant Sel as UserSelector
participant API as tRPC: suggestions
participant DB as Database
Admin->>UI: Open admin suggestions
UI->>API: listAdmin()
API->>DB: SELECT id,...,analystId, user{...}, analyst{...}
DB-->>API: Rows
API-->>UI: Suggestions with analyst and user data
Admin->>Sel: Open analyst selector
Sel->>API: user.listAll()
API->>DB: SELECT users
DB-->>API: Users
API-->>Sel: Users list
Admin->>Sel: Choose analyst (or "Não atribuído")
Sel-->>UI: onValueChange(analystId|null)
UI->>API: updateAdmin({ id, ..., analystId? })
API->>DB: UPDATE suggestion SET analystId = input.analystId ?? ctx.auth.userId
DB-->>API: OK
API-->>UI: Updated suggestion
UI-->>Admin: Reflect updated responsible analyst
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I twitch my whiskers at the queue,
Assigning minds to ideas anew.
A hop, a click—analysts align,
The backend nods, selects refine.
With gentle thumps I mark the trail,
Suggestions sorted—cotton-tail. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 34-adicionar-caixa-de-sugestões

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/app/(authenticated)/admin/suggestions/page.tsx (1)

367-383: Preserve null for analystId; don’t coerce to undefined

Coercing null to undefined breaks unassigning semantics and, combined with the server’s current fallback, will reassign to the current admin. Keep null intact.

Apply:

- if (updates.analystId !== undefined) {- updateData.analystId = updates.analystId ?? undefined- }+ if (updates.analystId !== undefined) {+ // Keep null to explicitly clear assignment; undefined means no change+ updateData.analystId = updates.analystId+ }
🧹 Nitpick comments (6)
src/server/api/routers/suggestions.ts (1)

110-127: Good switch to explicit select; consider trimming unused fields to reduce payload

Nice move to an explicit select for admin list; this typically improves performance and keeps types tight. If the UI ultimately displays the user's sector (user.setor) instead of the submitted sector, consider dropping submittedSector from the selection to cut payload, or align the mapping to avoid confusion.

Example minimal trim:

 select: {
id: true,
ideaNumber: true,
submittedName: true,
- submittedSector: true,
isNameVisible: true,
description: true,
contribution: true,
dateRef: true,
impact: true,
capacity: true,
effort: true,
finalScore: true,
finalClassification: true,
status: true,
rejectionReason: true,
analystId: true,
createdAt: true,
user: {
select: {
firstName: true,
lastName: true,
email: true,
setor: true,
},
},
analyst: {
select: {
firstName: true,
lastName: true,
email: true,
},
},
},
src/app/(authenticated)/admin/suggestions/page.tsx (5)

44-45: Type captures the new responsibility concept; document tri-state intent

Defining analystId: string | null in SuggestionLocal is fine. For clarity and to align with the server change, ensure the app treats:

  • undefined: no change
  • string: assign to that user
  • null: unassign

Would you like me to sweep the components for places where analystId is constructed to ensure they adhere to this tri-state convention?


222-222: _currentUser is fetched but never used; avoid prop drilling

_currentUser is passed down multiple levels but not used. Either remove it to reduce churn, or leverage it (e.g., to show “Você” next to the current user in UserSelector).


612-612: Remove unused _currentUser prop passed through components

_currentUser is threaded through IdeasAccordion and SuggestionItem but unused. Trim these props to simplify component signatures and avoid unnecessary rerenders.

High-level diff outline:

- _currentUser={_currentUser}

And in component props:

- _currentUser: RouterOutputs["user"]["me"] | undefined

Also applies to: 630-630, 689-689, 701-701, 779-779, 806-806


1040-1044: Unassign flow and UX: ensure it works end-to-end and consider disabling while saving

This call path must allow setting analystId to null. With the client/server fixes above, the “Não atribuído” option will clear the assignment. Consider temporarily disabling the selector while the update mutation for this suggestion is in-flight to avoid rapid toggles causing racey UI.

Example (conceptual; needs plumbing of a per-suggestion pending state):

- <UserSelector+ <UserSelector
value={s.analystId}
- onValueChange={(userId: string | null) => {+ onValueChange={(userId: string | null) => {
update(s.id, { analystId: userId })
}}
- />+ disabled={/* pending state for this suggestion's update */}+ />

129-215: Ensure “Não atribuído” shows selected state, improve typing, scalability, and confirm security

Selected state
The “Não atribuído” item should display a checkmark when value === null, matching the behavior of other rows.

Typing
Update getUserDisplayName to use (typeof allUsers)[number] so the parameter type can never be undefined.

Scalability
Currently api.user.listAll.useQuery() fetches every user on mount. If the user count grows, consider switching to a server-side search or paginated endpoint to keep the popover performant.

Security
Verified that user.listAll is implemented with adminProcedure in src/server/api/routers/user.ts (lines 21–23), so only admins can call it.

Apply these optional refactors:

- const getUserDisplayName = (user: typeof allUsers[0]) => {+ const getUserDisplayName = (user: (typeof allUsers)[number]) => {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`
}
return user.email
}
 <CommandItem
onSelect={() => {
onValueChange(null)
setOpen(false)
}}
className="text-muted-foreground"
>
- <Check className="mr-2 h-4 w-4 opacity-0" />+ <Check className={`mr-2 h-4 w-4 ${value === null ? "opacity-100" : "opacity-0"}`} />
Não atribuído
</CommandItem>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0891924 and 1728631.

📒 Files selected for processing (2)
  • src/app/(authenticated)/admin/suggestions/page.tsx (15 hunks)
  • src/server/api/routers/suggestions.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/(authenticated)/admin/suggestions/page.tsx (4)
src/trpc/react.tsx (2)
  • api (23-23)
  • RouterOutputs (37-37)
src/components/ui/popover.tsx (3)
  • Popover (31-31)
  • PopoverTrigger (31-31)
  • PopoverContent (31-31)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/components/ui/command.tsx (6)
  • Command (144-144)
  • CommandInput (146-146)
  • CommandList (147-147)
  • CommandEmpty (148-148)
  • CommandGroup (149-149)
  • CommandItem (150-150)
🔇 Additional comments (5)
src/server/api/routers/suggestions.ts (1)

162-162: Comment update improves clarity

The updated doc comment calling out analyst handling is helpful for future readers.

src/app/(authenticated)/admin/suggestions/page.tsx (4)

18-18: Icon import looks good

Imports are consistent with usage in this file.


20-21: Command/Popover UI imports are appropriate

Matches the new UserSelector implementation below.


113-113: Mapping analystId from DB is correct

Direct pass-through matches the server select.


313-338: Classification pools: good memoized mapping

Mapping tRPC results to local ClassItem[] is straightforward and readable.

kpis: z.array(z.string()).optional(),
status: StatusEnum.optional(),
rejectionReason: z.string().optional(),
analystId: z.string().optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Allow null to enable unassigning an analyst (tri-state: string | null | undefined)

Right now analystId is z.string().optional(). That makes it impossible to intentionally clear the responsible analyst: sending null fails validation; omitting the field (undefined) currently triggers a fallback (see Line 240) that will force-assign the current admin. Support null so the client can unassign.

Apply:

- analystId: z.string().optional(),+ // string = assign to user; null = unassign; undefined = do not change+ analystId: z.string().nullable().optional(),
📝 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.

Suggested change
analystId: z.string().optional(),
// string = assign to user; null = unassign; undefined = do not change
analystId: z.string().nullable().optional(),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 172, the Zod schema for
analystId should accept null so clients can explicitly unassign; change the
schema to allow string | null | undefined (e.g., make it nullable and optional).
Also adjust the handling around line 240 so the "fallback to current admin" only
runs when analystId is strictly undefined (preserve existing behavior for
omitted field) and treat a null value as an explicit unassign (do not replace it
with the current admin).

status: input.status,
rejectionReason: input.rejectionReason,
analystId: ctx.auth.userId,
analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not force-assign analyst on every admin update; honor undefined vs null

analystId: input.analystId ?? ctx.auth.userId reassigns the analyst to the current admin on any update that omits analystId. It also prevents unassigning even if the client sends null (because ?? coalesces null). This will silently overwrite the responsible analyst during unrelated updates (status, scores, etc.).

Use tri-state semantics:

  • undefined: don't touch analystId
  • string: assign to that user
  • null: clear the assignment

Apply:

- analystId: input.analystId ?? ctx.auth.userId, // Usar analystId fornecido ou fallback para usuário atual+ // Only modify when provided; allow null to clear+ ...(input.analystId !== undefined ? { analystId: input.analystId } : {}),

Optionally, if you want a one-time default assignment when there is no analyst yet, gate it explicitly:

// Before update, fetch current analystIdconstcurrent=awaitctx.db.suggestion.findUnique({where: {id: input.id},select: {analystId: true}});// In data:
...(input.analystId!==undefined
? {analystId: input.analystId}
: current?.analystId ? {} : {/* decide whether to set a default here or leave null */}),
🤖 Prompt for AI Agents
In src/server/api/routers/suggestions.ts around line 240, the current use of
"analystId: input.analystId ?? ctx.auth.userId" force-assigns the analyst on
every update and treats null as undefined; change this to tri-state handling:
fetch the current suggestion's analystId first, then when building the update
data only include analystId if input.analystId !== undefined (if string, set it;
if null, set it to null to clear), and do not fall back to ctx.auth.userId
implicitly — if you want a one-time default when there is no analyst, gate that
explicitly based on the fetched current value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@rbxyz