Conversation
📝 WalkthroughWalkthroughReplaced per-item proposal vote fetches with a single bulk user-votes query, adjusted proposal-votes query fetch behavior, and added explicit bootstrap-loading and init-error guards across chat components to avoid partial rendering. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as Client UI
participant QMgr as EcencyQueriesManager
participant Hive as Hive API (database_api)
UI->>QMgr: getUserProposalVotesQuery(voter)
QMgr->>Hive: list_proposal_votes({start: voter, order: "voter_proposal", limit:1000})
Hive-->>QMgr: ProposalVote[] (may include extra ordering results)
QMgr-->>UI: ProposalVote[] (filtered where vote.voter == voter)
note right of UI `#D6EAF8`: UI builds Set of proposal IDs\nand passes votedByViewer to items
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
apps/web/src/api/queries/get-user-proposal-votes-query.ts (1)
13-18: Remove redundant voter validation.The
enabledcheck on line 13 and the guard clause on lines 16-18 serve the same purpose. Theenabledcheck is more efficient as it prevents the query from running at all, making the guard clause unnecessary.🔎 Proposed refactoring to remove redundant guard clause
EcencyQueriesManager.generateClientServerQuery<ProposalVote[]>({ queryKey: [QueryIdentifiers.PROPOSAL_VOTES, "by_user", voter], enabled: !!voter && voter !== "", // Only run if voter is specified staleTime: 60 * 1000, // Cache for 1 minute queryFn: async () => { - if (!voter || voter === "") { - return []; - } - const response = (await client.call("database_api", "list_proposal_votes", {apps/web/src/app/proposals/_components/proposal-list-item/index.tsx (1)
3-3: Remove unuseduseMemoimport.The
useMemohook is no longer used after removing the client-side votes calculation logic. Clean up the import to keep dependencies lean.🔎 Proposed fix
-import React, { useMemo, useState } from "react"; +import React, { useState } from "react";
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
apps/web/src/api/queries/get-proposal-votes-query.tsapps/web/src/api/queries/get-user-proposal-votes-query.tsapps/web/src/api/queries/index.tsapps/web/src/app/chats/[id]/channel/_components/community-channel-client.tsxapps/web/src/app/chats/[id]/page.tsxapps/web/src/app/chats/_components/chats-client.tsxapps/web/src/app/chats/_components/chats-page-client.tsxapps/web/src/app/proposals/_components/proposal-list-item/index.tsxapps/web/src/app/proposals/_components/proposal-votes/index.tsxapps/web/src/app/proposals/_page.tsx
🧰 Additional context used
🧬 Code graph analysis (3)
apps/web/src/api/queries/get-user-proposal-votes-query.ts (2)
apps/web/src/api/hive.ts (1)
client(48-52)apps/web/src/api/operations.ts (1)
vote(352-371)
apps/web/src/api/queries/get-proposal-votes-query.ts (1)
apps/web/src/api/hive.ts (1)
client(48-52)
apps/web/src/app/proposals/_page.tsx (2)
apps/web/src/api/queries/get-user-proposal-votes-query.ts (1)
getUserProposalVotesQuery(10-35)apps/web/src/app/proposals/_components/proposal-list-item/index.tsx (1)
ProposalListItem(24-142)
🔇 Additional comments (11)
apps/web/src/app/chats/[id]/page.tsx (1)
36-50: LGTM! Proper loading and initialization guards.The addition of explicit loading and bootstrap checks ensures the chat UI only renders when initialization is complete, preventing potential runtime errors and improving user feedback.
apps/web/src/app/chats/_components/chats-page-client.tsx (2)
89-96: LGTM! Consistent bootstrap guard implementation.The loading guard ensures the channel view waits for bootstrap completion, aligning with the broader pattern across chat components in this PR.
98-106: LGTM! Improved no-channels message clarity.The refined conditional correctly distinguishes between "still loading" vs "no channels available" states, providing clearer user feedback.
apps/web/src/app/chats/_components/chats-client.tsx (1)
375-382: LGTM! Bootstrap guard prevents premature channel list rendering.The loading guard ensures the channel list waits for bootstrap completion, maintaining consistency with the initialization pattern applied across all chat components in this PR.
apps/web/src/api/queries/get-proposal-votes-query.ts (2)
23-26: LGTM: Improved query configuration for fresh data.The removal of
initialDataand addition ofstaleTime: 0ensures the query always refetches on mount, providing fresh proposal votes data. The comment clearly documents the reasoning.
29-35: Good refactoring: Cleaner parameter handling.The introduction of
startParamwith explicit type annotation improves code clarity and makes the pageParam fallback logic more readable.apps/web/src/api/queries/index.ts (1)
39-39: LGTM: New query export properly integrated.The new
get-user-proposal-votes-queryexport is correctly positioned and follows the existing pattern.apps/web/src/app/proposals/_page.tsx (2)
38-47: Excellent optimization: Single bulk fetch instead of per-item queries.This change significantly improves performance by fetching all user votes in one query and using a
Setfor O(1) lookup. The fallback chain from URL param to active user to empty string is well-designed.
219-223: Clean integration: votedByViewer prop properly computed and passed.The voted state is efficiently determined using Set membership and passed to
ProposalListItem. This aligns with the optimization goal of avoiding per-item queries.Note: This depends on the 1000 vote limit in
getUserProposalVotesQuery. If users can exceed 1000 votes, some proposals may incorrectly show as not voted.apps/web/src/api/queries/get-user-proposal-votes-query.ts (1)
20-26: This API choice is correct and intentional. The two queries have distinct purposes:get-user-proposal-votes-query.tsusesdatabase_apito fetch all votes by a specific user (usingby_voter_proposalordering), whileget-proposal-votes-query.tsusescondenser_apito fetch votes for a specific proposal (usingby_proposal_voterordering). Both endpoints support their respective parameters:database_apiaccepts named parameters withstatusfiltering and returns data wrapped in{proposal_votes: [...]}, whilecondenser_apiaccepts positional parameters and returns a plain array. The implementation is correct, including the defensive filter on lines 28-31 that ensures only the requesting user's votes are returned.apps/web/src/app/proposals/_components/proposal-list-item/index.tsx (1)
21-21: Optimization correctly implemented end-to-end.The refactor to accept
votedByVieweras a prop eliminates per-item vote queries, moving to a single bulk query viagetUserProposalVotesQuery. The parent component (_page.tsx) correctly implements this: it fetches all user votes once, builds a set of voted proposal IDs, and passes the boolean status to eachProposalListItem. The prop design is clean with a sensible default and clear documentation.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
apps/web/src/app/chats/[id]/channel/_components/community-channel-client.tsx (2)
26-26: Consider simplifying the dependency array.The dependency array includes both
data?.channelIdanddata. Sincedata?.channelIdwill change wheneverdatachanges, including both is redundant and may cause the effect to run more frequently than necessary.🔎 Proposed optimization
- }, [data?.channelId, data, router, params.id]); + }, [data, router, params.id]);The conditional check
if (data?.channelId)inside the effect will still work correctly with justdatain the dependencies.
40-42: Consider more robust error type checking.The error handling relies on substring matching (
error?.message.includes("username")), which can be fragile if the error message format changes. Consider using error codes or error types if available from the API.Note: This is an existing pattern in the codebase, not introduced by this PR, but worth considering for future refactoring.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/src/app/chats/[id]/channel/_components/community-channel-client.tsxapps/web/src/app/proposals/_page.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/src/app/proposals/_page.tsx (3)
apps/web/src/api/queries/get-account-full-query.ts (1)
getAccountFullQuery(6-43)apps/web/src/api/queries/get-user-proposal-votes-query.ts (1)
getUserProposalVotesQuery(10-35)apps/web/src/app/proposals/_components/proposal-list-item/index.tsx (1)
ProposalListItem(24-142)
🔇 Additional comments (7)
apps/web/src/app/chats/[id]/channel/_components/community-channel-client.tsx (3)
44-50: LGTM! Clear loading state.The explicit loading state with "Preparing the community channel…" provides good user feedback during the bootstrap process and aligns with the PR's objective of adding explicit bootstrap-loading guards.
52-72: Excellent fix for the missing channelId issue!This error handling directly addresses the concern raised in the previous review about users getting stuck in a "Redirecting…" state when
channelIdis missing. The implementation provides:
- A clear error message explaining the issue
- Contextual information (community name)
- A recovery action via the "Go to Chats" button
Great improvement to the user experience!
74-79: LGTM! Correct redirect flow.The final return correctly shows "Redirecting…" only when a valid
channelIdexists. TheuseEffectwill handle the actual navigation on the next tick. The comment on line 74 helpfully clarifies this intent.apps/web/src/app/proposals/_page.tsx (4)
11-11: LGTM: Imports support the bulk-vote optimization.The new imports (
getUserProposalVotesQueryanduseActiveAccount) are correctly used in the voter resolution and vote-fetching logic below.Also applies to: 18-18
33-33: LGTM: Voter resolution logic is correct.The fallback chain (
?voterparam → active user → empty string) correctly determines whose votes to highlight. WhenvoterParamis empty, the query is disabled (pergetUserProposalVotesQueryimplementation), avoiding unnecessary API calls. This optimization replaces per-proposal fetches with a single bulk query.Also applies to: 38-41
224-228: LGTM: Efficient lookup using the memoized Set.The
votedByViewerprop is correctly passed via a constant-time Set lookup. This cleanly replaces per-item vote fetches with a single bulk query.Note:
getUserProposalVotesQueryfetches up to 1000 votes (seeapps/web/src/api/queries/get-user-proposal-votes-query.ts). While it's unlikely a user votes on >1000 proposals, consider whether pagination or a higher limit might be needed in the future.
44-52: Vote Set construction is safe and efficient.The implementation correctly uses optional chaining (
v.proposal?.proposal_id) and filters undefined values with a type predicate. The memoized Set provides O(1) lookup for thevotedByViewerprop and theproposal_idfield is confirmed in the Proposal entity.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.