-
Notifications
You must be signed in to change notification settings - Fork 4
Feat/evoting #273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/evoting #273
Conversation
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including You can disable this status message by setting the WalkthroughThis update introduces a comprehensive eVoting platform and API backend. It adds new authentication, poll, and voting logic, TypeORM entity definitions, migrations, and utility modules for JWT and TypeORM integration. The frontend receives new authentication pages, navigation, enhanced poll creation, and refactored UI components. Some legacy plugins are removed and configuration files are added or updated for Docker, TypeScript, and package management. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend (eVoting)
participant AuthClient
participant API Server
participant Database
User->>Frontend (eVoting): Accesses protected page
Frontend (eVoting)->>AuthClient: Check session
alt Not authenticated
Frontend (eVoting)->>User: Redirect to /login
User->>Frontend (eVoting): Submits login form
Frontend (eVoting)->>AuthClient: signIn(email, password)
AuthClient->>API Server: POST /api/auth/*
API Server->>Database: Query user credentials
Database-->>API Server: User record
API Server-->>AuthClient: Auth token/session
AuthClient-->>Frontend (eVoting): Session established
Frontend (eVoting)->>User: Redirect to app
else Authenticated
Frontend (eVoting)->>User: Render app layout
end
sequenceDiagram
participant User
participant Frontend (eVoting)
participant API Server
participant Database
User->>Frontend (eVoting): Submits poll creation form
Frontend (eVoting)->>API Server: POST /poll (with poll data)
API Server->>Database: Insert poll record
Database-->>API Server: Poll created
API Server-->>Frontend (eVoting): Poll confirmation
User->>Frontend (eVoting): Casts vote
Frontend (eVoting)->>API Server: POST /poll/:id/vote (with vote data)
API Server->>Database: Validate & insert vote
Database-->>API Server: Vote recorded
API Server-->>Frontend (eVoting): Vote confirmation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 74
♻️ Duplicate comments (1)
platforms/evoting-api/src/database/old/migrations/1749281568709-migration.ts (1)
1-20
: Duplicate migration exists in pictique-api.This migration is nearly identical to
platforms/pictique-api/src/database/migrations/1749281568709-migration.ts
. Consider whether this code duplication is intentional or if these should be consolidated.The migration logic itself appears correct for converting from direct message recipients to a chat-based model.
🧹 Nitpick comments (32)
infrastructure/control-panel/project.inlang/.gitignore (1)
1-1
: Explicitly target the directory with a trailing slashAppending
/
clarifies that the ignore rule applies to thecache
directory rather than any file namedcache
.-cache +cache/evoting.compose.yml (1)
11-12
: Consider conditional port exposure.Exposing PostgreSQL port 5432 directly may not be necessary if the application only connects via Docker network. Consider making it conditional.
ports: - - "5432:5432" + - "${POSTGRES_PORT:-5432}:5432"This allows disabling external access by setting
POSTGRES_PORT=""
in production.platforms/evoting-api/src/database/entities/User.ts (1)
17-18
: Consider using varchar for image field.Using
text
type for image URLs may be inefficient. Consider usingvarchar
with appropriate length limit.- @Column("text", { name: "image", nullable: true }) + @Column("varchar", { name: "image", length: 500, nullable: true })platforms/evoting-api/src/database/entities/Verification.ts (1)
8-12
: Consider adding constraints to identifier and value fields.For verification entities, you might want to add constraints like uniqueness on identifier or length limits on value depending on the verification type (email codes, phone OTP, etc.).
Consider adding appropriate constraints based on your verification requirements:
- @Column("text", { name: "identifier", nullable: false }) + @Column("varchar", { name: "identifier", length: 255, nullable: false }) identifier: string; - @Column("text", { name: "value", nullable: false }) + @Column("varchar", { name: "value", length: 255, nullable: false }) value: string;platforms/eVoting/src/app/(app)/layout.tsx (2)
16-20
: Add loading state protection and consider infinite redirect scenarios.The authentication logic is correct, but consider adding protection against edge cases where the session state might oscillate.
useEffect(() => { - if (!session.data && !session.isPending) { + if (!session.data && !session.isPending && router) { router.push("/login"); } }, [session.data, session.isPending, router]);
22-24
: Enhance loading UI for better user experience.Consider replacing the basic loading text with a proper loading component or skeleton UI for better user experience.
if (session.isPending) { - return <div>Loading...</div>; // Optional: show loading UI + return ( + <div className="flex items-center justify-center min-h-screen"> + <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div> + </div> + ); }platforms/evoting-api/src/database/old/migrations/1749561069022-migration.ts (1)
7-7
: Add length constraints to character varying columns.The character varying columns lack length constraints which could lead to storage inefficiency and potential issues with very long strings.
-await queryRunner.query(`CREATE TABLE "__web3_id_mapping" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "localId" character varying NOT NULL, "metaEnvelopeId" character varying NOT NULL, "entityType" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_4c57c87c4ee60f42d9c6b0861c2" PRIMARY KEY ("id"))`); +await queryRunner.query(`CREATE TABLE "__web3_id_mapping" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "localId" character varying(255) NOT NULL, "metaEnvelopeId" character varying(255) NOT NULL, "entityType" character varying(100) NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_4c57c87c4ee60f42d9c6b0861c2" PRIMARY KEY ("id"))`);platforms/eVoting/src/app/(auth)/register/page.tsx (2)
48-48
: Fix grammatical error in placeholder text.-placeholder="Choose a email" +placeholder="Choose an email"
36-36
: Add error handling for missing images.The hardcoded image sources could fail to load, breaking the UI. Consider adding fallback handling or using Next.js Image component.
-<img src="/Logo.png" alt="eVoting Logo" /> +<img src="/Logo.png" alt="eVoting Logo" onError={(e) => { (e.target as HTMLImageElement).style.display = 'none'; }} />Also applies to: 84-84
platforms/evoting-api/tsconfig.json (1)
4-4
: Consider using ES modules for modern Node.js.While CommonJS works fine, consider migrating to ES modules for better tree-shaking and modern JavaScript ecosystem compatibility:
-"module": "commonjs", +"module": "ESNext", +"moduleResolution": "bundler",Note: This would require updating import/export syntax throughout the codebase and package.json configuration.
platforms/evoting-api/src/database/data-source.ts (1)
11-11
: Verify the .env file path resolution.The path resolution goes up 4 levels (
../../../../.env
) which assumes a specific directory structure. This could break if the file structure changes.Consider using a more robust approach:
-config({ path: path.resolve(__dirname, "../../../../.env") }); +config(); // Uses process.cwd() by default, or specify NODE_ENV-based pathsplatforms/evoting-api/src/middleware/auth.ts (1)
24-25
: Consider caching user lookups for performance.Each authenticated request triggers a database query to fetch the user. For high-traffic applications, this could become a performance bottleneck.
Consider implementing user caching or including essential user data in the JWT payload to reduce database hits.
platforms/evoting-api/src/database/entities/Session.ts (1)
11-12
: Consider token field security implications.Storing the full token in plain text could be a security risk if the database is compromised. Consider storing a hash of the token instead.
For enhanced security, consider hashing the token:
-@Column("text", { name: "token", nullable: false }) -token: string; +@Column("text", { name: "tokenHash", nullable: false }) +tokenHash: string;Then hash tokens before storage and compare hashes during validation.
platforms/evoting-api/src/database/old/migrations/1749281568709-migration.ts (1)
10-10
: Consider CASCADE delete behavior for referential integrity.The foreign key constraints use
ON DELETE NO ACTION
which may leave orphaned records. For a chat system, consider whether messages should be deleted when a chat is deleted.- await queryRunner.query(`ALTER TABLE "messages" ADD CONSTRAINT "FK_36bc604c820bb9adc4c75cd4115" FOREIGN KEY ("chatId") REFERENCES "chat"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "messages" ADD CONSTRAINT "FK_36bc604c820bb9adc4c75cd4115" FOREIGN KEY ("chatId") REFERENCES "chat"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);Also applies to: 17-17
platforms/evoting-api/src/database/old/migrations/1749032877158-migration.ts (1)
6-36
: Consider breaking large migrations into smaller chunks.This migration creates many tables and relationships in a single operation. For better maintainability and easier debugging, consider splitting this into smaller, focused migrations (e.g., core entities, then relationships, then indexes).
platforms/evoting-api/src/database/old/entities/Message.ts (2)
19-20
: Consider specifying explicit foreign key column names.While TypeORM will infer foreign key names, being explicit improves clarity and prevents potential issues during schema changes.
- @ManyToOne(() => User) + @ManyToOne(() => User) + @JoinColumn({ name: "senderId" }) sender!: User; - @ManyToOne(() => Chat, (e) => e.messages) + @ManyToOne(() => Chat, (e) => e.messages) + @JoinColumn({ name: "chatId" }) chat!: Chat;Also applies to: 25-26
22-23
: Consider adding text length constraints for performance.Large text fields without constraints can impact database performance. Consider adding a reasonable maximum length or using appropriate column type.
- @Column("text") + @Column("text", { length: 10000 }) // or appropriate limit text!: string;platforms/evoting-api/src/index.ts (2)
1-21
: Clean up commented-out imports for better maintainability.The active imports are well-structured, but the extensive commented-out imports create visual clutter and may confuse future developers about which features are actually implemented.
Consider removing commented-out imports or adding a clear TODO comment explaining the implementation plan:
-// import { AuthController } from "./controllers/AuthController"; -// import { CommentController } from "./controllers/CommentController"; -// import { MessageController } from "./controllers/MessageController"; -// import { PostController } from "./controllers/PostController"; -// import { UserController } from "./controllers/UserController"; -// import { WebhookController } from "./controllers/WebhookController"; +// TODO: Implement social media features (posts, comments, messages, webhooks)
52-137
: Consider removing extensive commented-out route definitions.This large block of commented code (85+ lines) creates maintenance overhead and confusion about implemented features. Consider either implementing these routes or removing them to keep the codebase clean.
If these routes are planned for future implementation, consider:
- Moving them to a separate documentation file
- Creating a TODO list in the README
- Implementing them incrementally in separate PRs
This will improve code readability and reduce the chance of merge conflicts.
platforms/evoting-api/src/database/entities/Poll.ts (1)
31-32
: Consider limitations of simple-array storage for options.The
simple-array
column type stores options as comma-separated values, which could cause issues if option text contains commas. For a more robust solution, consider using JSON storage or a separate PollOption entity.-@Column("simple-array") -options: string[]; // stored as comma-separated values +@Column("json") +options: string[]; // stored as JSON arrayOr for more complex poll options in the future:
@OneToMany(() => PollOption, (option) => option.poll) options: PollOption[];platforms/evoting-api/src/database/entities/Account.ts (1)
1-51
: Consider adding indexes for performance optimizationAdd indexes on frequently queried columns like
userId
,accountId
, andproviderId
to improve query performance.Add indexes to the entity:
+import { Column, Entity, Index } from "typeorm"; @Entity("account") +@Index(["userId"]) +@Index(["accountId", "providerId"]) export class Account {platforms/evoting-api/src/database/entities/Vote.ts (1)
19-22
: Fix misleading comment for RankVoteDataThe comment states "1 = top pick, 2 = next, etc." but the type definition shows
points: number
, which is inconsistent. Based on the context, this should clarify the ranking system.export type RankVoteData = { option: string; - points: number; // 1 = top pick, 2 = next, etc. + rank: number; // 1 = top pick, 2 = second choice, etc. }[];platforms/eVoting/src/components/navigation.tsx (1)
103-109
: Use Next.js Link component for logout consistencyFor consistency with other navigation items and to benefit from Next.js prefetching, use the
Link
component for logout navigation.- <DropdownMenuItem asChild> - <a - href="/logout" - className="flex items-center w-full" - > - <LogOut className="w-4 h-4 mr-2" /> - Logout - </a> - </DropdownMenuItem> + <DropdownMenuItem asChild> + <Link + href="/logout" + className="flex items-center w-full" + > + <LogOut className="w-4 h-4 mr-2" /> + Logout + </Link> + </DropdownMenuItem>Apply the same change to the mobile menu logout link at lines 216-224.
Also applies to: 216-224
platforms/eVoting/src/app/(app)/create/page.tsx (2)
92-94
: Implement poll creation API callThe form submission handler is empty. The TODO comment indicates this needs implementation.
Would you like me to help implement the API call to create a poll? Based on the codebase structure, this would likely call the
/polls
endpoint with the form data.
325-326
: Consider using stable keys instead of array indicesWhile the comment acknowledges the use of array indices as keys, this can cause issues with form state when options are reordered. Consider generating stable IDs for each option.
You could maintain option objects with IDs instead of just strings:
type OptionItem = { id: string; value: string }; const [options, setOptions] = useState<OptionItem[]>([ { id: crypto.randomUUID(), value: "" }, { id: crypto.randomUUID(), value: "" } ]);Then use
option.id
as the key instead of the index.platforms/evoting-api/src/utils/typeorm-adapter.ts (1)
286-317
: Consider pagination limits for findManyThe findMany method defaults to 100 records but this might be too high for some use cases.
const result = await repository.find({ where: findOptions, - take: limit || 100, + take: Math.min(limit || 20, 100), // Cap at 100, default to 20 skip: offset || 0,This prevents potential performance issues from large result sets while still allowing flexibility.
infrastructure/web3-adapter/src/evault/evault.js (1)
127-128
: Remove or explain the biome-ignore commentThe biome-ignore comment should either be removed or include a proper explanation.
- // biome-ignore lint/style/noNonNullAssertion: <explanation> + // lastError is guaranteed to be set because we only reach here after at least one attempt throw lastError;platforms/evoting-api/src/database/old/entities/User.ts (1)
35-36
: Clarify the purpose of the "ename" field.The field name
ename
is ambiguous. Consider using a more descriptive name likeexternalName
,evaultName
, or whatever it represents in your domain model.infrastructure/web3-adapter/src/mapper/mapper.js (4)
1-5
: Use ES modules instead of CommonJS for consistency.The file uses CommonJS exports while the TypeORM entities use ES modules. Consider using ES modules throughout the codebase for consistency.
-"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getValueByPath = getValueByPath; -exports.fromGlobal = fromGlobal; -exports.toGlobal = toGlobal; +export { getValueByPath, fromGlobal, toGlobal };
43-46
: Improve string parsing logic for robustness.The current parsing logic using
includes
andsplit
is fragile and could fail with nested parentheses or edge cases.Consider using a regex pattern for more robust parsing:
- if (value.includes("(") && value.includes(")")) { - value = value.split("(")[1].split(")")[0]; - } + const match = value.match(/\(([^)]+)\)/); + if (match) { + value = match[1]; + }
220-224
: Ensure consistent null handling in async operations.The code uses nullish coalescing (
??
) inconsistently. Array mapping returnsundefined
while single values might returnnull
.if (Array.isArray(value)) { - value = await Promise.all(value.map(async (v) => (await mappingStore.getGlobalId(v)) ?? undefined)); + value = await Promise.all(value.map(async (v) => { + const globalId = await mappingStore.getGlobalId(v); + return globalId ?? null; + })); } else { - value = (await mappingStore.getGlobalId(value)) ?? undefined; + value = (await mappingStore.getGlobalId(value)) ?? null; }
234-234
: Remove or update the source map reference.The source map file reference at the end suggests this is compiled code. If this is the source file, remove the source map comment. If it's compiled output, it shouldn't be in the source repository.
-//# sourceMappingURL=mapper.js.map
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (9)
infrastructure/web3-adapter/src/db/index.js.map
is excluded by!**/*.map
infrastructure/web3-adapter/src/db/mapping.db.js.map
is excluded by!**/*.map
infrastructure/web3-adapter/src/evault/evault.js.map
is excluded by!**/*.map
infrastructure/web3-adapter/src/index.js.map
is excluded by!**/*.map
infrastructure/web3-adapter/src/mapper/mapper.js.map
is excluded by!**/*.map
infrastructure/web3-adapter/src/mapper/mapper.types.js.map
is excluded by!**/*.map
platforms/eVoting/public/Logo.png
is excluded by!**/*.png
platforms/eVoting/public/W3DS.svg
is excluded by!**/*.svg
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (50)
evoting.compose.yml
(1 hunks)infrastructure/control-panel/project.inlang/.gitignore
(1 hunks)infrastructure/control-panel/project.inlang/cache/plugins/2sy648wh9sugi
(0 hunks)infrastructure/control-panel/project.inlang/cache/plugins/ygx0uiahq6uw
(0 hunks)infrastructure/web3-adapter/src/db/index.js
(1 hunks)infrastructure/web3-adapter/src/db/mapping.db.js
(1 hunks)infrastructure/web3-adapter/src/evault/evault.js
(1 hunks)infrastructure/web3-adapter/src/index.js
(1 hunks)infrastructure/web3-adapter/src/mapper/mapper.js
(1 hunks)infrastructure/web3-adapter/src/mapper/mapper.types.js
(1 hunks)platforms/eVoting/package.json
(1 hunks)platforms/eVoting/src/app/(app)/create/page.tsx
(7 hunks)platforms/eVoting/src/app/(app)/layout.tsx
(1 hunks)platforms/eVoting/src/app/(auth)/login/page.tsx
(1 hunks)platforms/eVoting/src/app/(auth)/logout/page.tsx
(1 hunks)platforms/eVoting/src/app/(auth)/register/page.tsx
(1 hunks)platforms/eVoting/src/components/navigation.tsx
(8 hunks)platforms/eVoting/src/components/ui/card.tsx
(1 hunks)platforms/eVoting/src/components/ui/dropdown-menu.tsx
(1 hunks)platforms/eVoting/src/lib/auth-client.ts
(1 hunks)platforms/eVoting/tsconfig.json
(2 hunks)platforms/evoting-api/package.json
(1 hunks)platforms/evoting-api/reset.sh
(1 hunks)platforms/evoting-api/src/auth.ts
(1 hunks)platforms/evoting-api/src/controllers/poll.controller.ts
(1 hunks)platforms/evoting-api/src/database/data-source.ts
(1 hunks)platforms/evoting-api/src/database/entities/Account.ts
(1 hunks)platforms/evoting-api/src/database/entities/Poll.ts
(1 hunks)platforms/evoting-api/src/database/entities/Session.ts
(1 hunks)platforms/evoting-api/src/database/entities/User.ts
(1 hunks)platforms/evoting-api/src/database/entities/Verification.ts
(1 hunks)platforms/evoting-api/src/database/entities/Vote.ts
(1 hunks)platforms/evoting-api/src/database/migrations/1754132648735-migration.ts
(1 hunks)platforms/evoting-api/src/database/old/entities/Chat.ts
(1 hunks)platforms/evoting-api/src/database/old/entities/Comment.ts
(1 hunks)platforms/evoting-api/src/database/old/entities/Message.ts
(1 hunks)platforms/evoting-api/src/database/old/entities/MessageReadStatus.ts
(1 hunks)platforms/evoting-api/src/database/old/entities/Post.ts
(1 hunks)platforms/evoting-api/src/database/old/entities/User.ts
(1 hunks)platforms/evoting-api/src/database/old/migrations/1749032877158-migration.ts
(1 hunks)platforms/evoting-api/src/database/old/migrations/1749281568709-migration.ts
(1 hunks)platforms/evoting-api/src/database/old/migrations/1749283608071-migration.ts
(1 hunks)platforms/evoting-api/src/database/old/migrations/1749561069022-migration.ts
(1 hunks)platforms/evoting-api/src/index.ts
(1 hunks)platforms/evoting-api/src/middleware/auth.ts
(1 hunks)platforms/evoting-api/src/services/poll.service.ts
(1 hunks)platforms/evoting-api/src/types/express.d.ts
(1 hunks)platforms/evoting-api/src/utils/jwt.ts
(1 hunks)platforms/evoting-api/src/utils/typeorm-adapter.ts
(1 hunks)platforms/evoting-api/tsconfig.json
(1 hunks)
💤 Files with no reviewable changes (2)
- infrastructure/control-panel/project.inlang/cache/plugins/ygx0uiahq6uw
- infrastructure/control-panel/project.inlang/cache/plugins/2sy648wh9sugi
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: in the metastate prototype project, prefer using centralized type definitions from `$lib/types` over...
Learnt from: Sahil2004
PR: MetaState-Prototype-Project/prototype#193
File: platforms/metagram/src/lib/store/store.svelte.ts:0-0
Timestamp: 2025-06-07T04:59:24.520Z
Learning: In the MetaState prototype project, prefer using centralized type definitions from `$lib/types` over importing interfaces from component files for better type organization and to avoid circular dependencies.
Applied to files:
infrastructure/web3-adapter/src/mapper/mapper.types.js
🧬 Code Graph Analysis (18)
platforms/eVoting/src/app/(auth)/register/page.tsx (2)
platforms/eVoting/src/lib/auth-client.ts (1)
authClient
(2-5)platforms/eVoting/src/components/ui/card.tsx (2)
Card
(80-80)CardHeader
(81-81)
platforms/eVoting/src/components/ui/dropdown-menu.tsx (1)
infrastructure/eid-wallet/src/lib/utils/mergeClasses.ts (1)
cn
(4-6)
platforms/eVoting/src/components/ui/card.tsx (1)
infrastructure/eid-wallet/src/lib/utils/mergeClasses.ts (1)
cn
(4-6)
platforms/evoting-api/src/database/old/entities/MessageReadStatus.ts (2)
platforms/evoting-api/src/database/old/entities/User.ts (1)
Entity
(15-77)platforms/evoting-api/src/database/old/entities/Message.ts (1)
Entity
(14-39)
platforms/evoting-api/src/middleware/auth.ts (2)
platforms/evoting-api/src/utils/jwt.ts (1)
verifyToken
(9-15)platforms/evoting-api/src/database/data-source.ts (1)
AppDataSource
(25-25)
platforms/evoting-api/src/index.ts (2)
platforms/evoting-api/src/database/data-source.ts (1)
AppDataSource
(25-25)platforms/evoting-api/src/auth.ts (1)
auth
(5-11)
platforms/evoting-api/src/database/entities/Session.ts (3)
platforms/evoting-api/src/database/entities/Account.ts (1)
Entity
(3-51)platforms/evoting-api/src/database/entities/User.ts (1)
Entity
(3-33)platforms/evoting-api/src/database/entities/Verification.ts (1)
Entity
(3-22)
platforms/eVoting/src/app/(auth)/logout/page.tsx (1)
platforms/eVoting/src/lib/auth-client.ts (1)
authClient
(2-5)
platforms/evoting-api/src/database/old/migrations/1749281568709-migration.ts (1)
platforms/pictique-api/src/database/migrations/1749281568709-migration.ts (2)
Migration1749281568709
(3-20)up
(6-11)
platforms/eVoting/src/components/navigation.tsx (3)
platforms/eVoting/src/app/(app)/page.tsx (1)
Home
(28-354)platforms/eVoting/src/lib/auth-client.ts (1)
authClient
(2-5)infrastructure/eid-wallet/src/lib/ui/Button/index.ts (1)
Icon
(5-5)
platforms/evoting-api/src/controllers/poll.controller.ts (1)
platforms/evoting-api/src/services/poll.service.ts (1)
PollService
(52-200)
platforms/evoting-api/src/database/old/entities/Post.ts (3)
platforms/evoting-api/src/database/old/entities/Chat.ts (1)
Entity
(14-38)platforms/evoting-api/src/database/old/entities/Comment.ts (1)
Entity
(5-35)platforms/evoting-api/src/database/old/entities/User.ts (1)
Entity
(15-77)
platforms/evoting-api/src/database/old/entities/Comment.ts (2)
platforms/evoting-api/src/database/old/entities/Post.ts (1)
Entity
(5-41)platforms/evoting-api/src/database/old/entities/User.ts (1)
Entity
(15-77)
platforms/evoting-api/src/database/entities/Vote.ts (1)
platforms/evoting-api/src/database/entities/Poll.ts (1)
Entity
(11-48)
platforms/evoting-api/src/database/old/entities/Message.ts (3)
platforms/evoting-api/src/database/old/entities/Chat.ts (1)
Entity
(14-38)platforms/evoting-api/src/database/old/entities/MessageReadStatus.ts (1)
Entity
(12-31)platforms/evoting-api/src/database/old/entities/User.ts (1)
Entity
(15-77)
infrastructure/web3-adapter/src/index.js (2)
infrastructure/web3-adapter/src/mapper/mapper.js (2)
result
(49-49)result
(136-136)infrastructure/web3-adapter/src/index.ts (1)
Web3Adapter
(9-156)
platforms/evoting-api/src/database/old/entities/User.ts (5)
platforms/evoting-api/src/database/old/entities/Chat.ts (1)
Entity
(14-38)platforms/evoting-api/src/database/old/entities/Comment.ts (1)
Entity
(5-35)platforms/evoting-api/src/database/old/entities/MessageReadStatus.ts (1)
Entity
(12-31)platforms/evoting-api/src/database/old/entities/Post.ts (1)
Entity
(5-41)platforms/evoting-api/src/database/old/entities/Message.ts (1)
Entity
(14-39)
infrastructure/web3-adapter/src/evault/evault.js (1)
infrastructure/web3-adapter/src/evault/evault.ts (1)
EVaultClient
(118-387)
🪛 GitHub Actions: Check Lint
platforms/eVoting/package.json
[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Run 'pnpm install --no-frozen-lockfile' to update the lockfile.
🪛 GitHub Actions: Check Format
platforms/eVoting/package.json
[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Run 'pnpm install --no-frozen-lockfile' to update the lockfile.
🪛 GitHub Actions: Check Code
platforms/eVoting/package.json
[error] 1-1: pnpm install failed due to outdated lockfile. The pnpm-lock.yaml is not up to date with package.json dependencies. Use 'pnpm install --no-frozen-lockfile' to bypass this in CI.
🔇 Additional comments (32)
platforms/eVoting/tsconfig.json (1)
4-8
: LGTM! Formatting improvement enhances readability.The multi-line array formatting makes the TypeScript configuration more readable and maintainable without changing any functional behavior. The compiler options are appropriate for a Next.js eVoting platform.
Also applies to: 26-28, 31-37, 38-40
platforms/evoting-api/src/auth.ts (1)
5-11
: LGTM! Good authentication setup.The authentication configuration follows good practices by using environment variables for trusted origins and enabling email/password authentication through the betterAuth library.
platforms/evoting-api/src/types/express.d.ts (1)
1-9
: LGTM! Proper TypeScript declaration augmentation.The Express namespace augmentation correctly extends the Request interface with the optional user property, following TypeScript best practices for declaration merging. This enables type-safe access to authenticated user data throughout the API.
platforms/eVoting/src/components/ui/dropdown-menu.tsx (1)
1-201
: LGTM! Consistent formatting improvements.The formatting changes improve code consistency with proper semicolon usage, indentation, and line breaks. The component logic and functionality remain unchanged, and the implementation follows React best practices with proper forwardRef usage and TypeScript typing.
platforms/eVoting/src/components/ui/card.tsx (2)
26-26
: Note the padding reduction in CardHeader.The padding was reduced from
p-6
top-4
. Ensure this visual change aligns with the intended design specifications.
1-86
: LGTM! Clean formatting improvements.The formatting changes improve code consistency and readability. All card components maintain proper TypeScript typing and React forwardRef patterns.
platforms/eVoting/src/app/(app)/layout.tsx (1)
1-32
: Enable server-side authentication in the eVoting APIThe eVoting backend currently has its authentication imports and middleware commented out, leaving all endpoints unprotected. You should re-enable
authMiddleware
(and applyauthGuard
to individual routes as needed) to ensure sensitive operations cannot be accessed without a valid session.• File:
platforms/evoting-api/src/index.ts
- Uncomment the import of
authMiddleware
/authGuard
- Re-apply the middleware to all routes below
Suggested diff:
--- a/platforms/evoting-api/src/index.ts +++ b/platforms/evoting-api/src/index.ts @@ -// import { authGuard, authMiddleware } from "./middleware/auth"; +import { authGuard, authMiddleware } from "./middleware/auth"; @@ -// app.use(authMiddleware); // Apply auth middleware to all routes below +app.use(authMiddleware); // Apply auth middleware to all routes belowThen, for any public route that should remain open, explicitly skip the guard; otherwise, add
authGuard
to protect individual handlers.Likely an incorrect or invalid review comment.
platforms/evoting-api/tsconfig.json (1)
1-23
: Configuration looks good for TypeORM backend.The TypeScript configuration is well-suited for a TypeORM-based backend project. The decorator support and relaxed property initialization are appropriate for entity definitions.
platforms/evoting-api/src/database/data-source.ts (2)
16-16
: LGTM: Synchronization disabled for production safety.Good practice to disable synchronization in production environments to prevent accidental schema changes.
1-1
: reflect-metadata is already imported at application entry pointThe
reflect-metadata
import indata-source.ts
can be safely ignored—it's loaded in your app bootstrap:• Entry-point import:
platforms/evoting-api/src/index.ts:1 →import "reflect-metadata";
No changes needed here.
Likely an incorrect or invalid review comment.
platforms/evoting-api/src/database/old/entities/Chat.ts (2)
1-38
: Question: Why is this entity in the "old" directory?The file path suggests this is legacy code (
platforms/evoting-api/src/database/old/entities/Chat.ts
), but it's being added as a new file. This could indicate:
- Migration from old schema to new schema
- Accidentally placed in wrong directory
- Legacy code being reintroduced
Please clarify the intent and consider if this belongs in the main entities directory instead.
25-31
: LGTM: Proper many-to-many relationship configuration.The join table configuration is well-defined with explicit column names and references. This provides good control over the database schema.
platforms/evoting-api/src/middleware/auth.ts (2)
12-15
: LGTM: Proper bearer token extraction with fallback.The middleware correctly checks for the Bearer token format and gracefully continues without authentication if not present, which is appropriate for optional authentication middleware.
39-44
: LGTM: Clean separation of concerns.The
authGuard
function provides a clean way to enforce authentication on protected routes, with appropriate error response.platforms/evoting-api/src/database/entities/Session.ts (2)
5-6
: LGTM: Proper UUID primary key configuration.The varchar length of 36 characters is appropriate for UUID format, and using string type is correct for TypeORM UUID handling.
28-32
: LGTM: Appropriate nullable fields for session metadata.IP address and user agent are correctly marked as nullable since they may not always be available or relevant.
platforms/evoting-api/package.json (1)
10-13
: TypeORM migration scripts look correct.The migration scripts properly reference the data source and follow TypeORM conventions. The script structure supports both generation and execution of migrations.
platforms/evoting-api/src/database/old/migrations/1749032877158-migration.ts (2)
6-36
: Comprehensive schema creation looks well-designed.The migration creates a solid foundation for social media functionality with proper relationships, indexing, and CASCADE behavior on join tables. The schema design follows good database practices.
1-4
: Ignore mischaracterization of the “old” schema
The migrations and entities underplatforms/evoting-api/src/database/old
are for the legacy messaging feature (Chat, Comment, Message, etc.), not for eVoting. The file1749032877158-migration.ts
belongs to that legacy schema and doesn’t introduce any new eVoting tables. You can disregard the suggestion to fold these into the main schema.Likely an incorrect or invalid review comment.
platforms/evoting-api/src/database/old/entities/Message.ts (1)
14-39
: Entity structure follows good TypeORM patterns.The Message entity is well-structured with appropriate relationships and follows the established patterns from other entities in the schema.
platforms/evoting-api/src/index.ts (2)
24-32
: LGTM! Proper database initialization with error handling.The database initialization follows TypeORM best practices with appropriate error handling and process termination on failure.
35-47
: LGTM! Comprehensive CORS configuration.The CORS setup properly handles authentication, webhooks, and various HTTP methods with appropriate fallback for development.
platforms/evoting-api/src/database/old/migrations/1749283608071-migration.ts (2)
3-30
: LGTM! Well-structured migration with proper rollback support.The migration correctly implements the transition from a simple
isRead
boolean to a granular per-user read status system. The SQL operations are properly ordered and the down migration correctly reverses all changes.
12-15
: Good foreign key constraint design.The different cascade behaviors are well-chosen:
message_read_status
uses NO ACTION to preserve read receipt historychat_participants
uses CASCADE for automatic cleanupThis design maintains data integrity while supporting the expected business logic.
platforms/evoting-api/src/database/old/entities/Comment.ts (1)
5-35
: LGTM! Well-designed Comment entity with proper relationships.The entity structure follows TypeORM best practices:
- Proper UUID primary key generation
- Clear many-to-one relationships with User and Post
- Explicit join table configuration for the likes relationship
- Standard audit columns and archival flag
The relationships align well with the referenced User and Post entities.
platforms/evoting-api/src/database/migrations/1754132648735-migration.ts (1)
6-11
: LGTM! Proper authentication schema setup.The migration creates a solid foundation for the authentication system with appropriate table structures for better-auth integration:
- Proper UUID column sizing (36 characters)
- Appropriate timestamp defaults and nullable fields
- Email verification with sensible default
platforms/evoting-api/src/database/entities/Poll.ts (1)
19-29
: LGTM! Well-defined poll configuration enums.The mode and visibility enums provide good flexibility:
- Mode options support different voting mechanisms (normal choice, point allocation, ranking)
- Visibility controls access appropriately
- Sensible defaults for both enums
platforms/evoting-api/src/database/entities/Vote.ts (1)
51-59
: Well-designed flexible vote data structureThe use of JSONB with discriminated union types (
VoteDataByMode
) provides excellent flexibility while maintaining type safety. This design elegantly handles different voting modes without requiring separate tables.platforms/eVoting/src/components/navigation.tsx (1)
149-157
: Good accessibility improvementsThe addition of keyboard event handlers, proper ARIA labels, and role attributes to the mobile menu backdrop improves accessibility for keyboard and screen reader users.
platforms/eVoting/src/app/(app)/create/page.tsx (1)
126-291
: Well-designed voting mode and visibility UIThe form provides an excellent user experience with:
- Clear visual representation of voting modes with icons and descriptions
- Intuitive radio button styling that highlights the selected option
- Proper accessibility with label associations
- Good use of Tailwind classes for consistent styling
platforms/evoting-api/src/database/old/entities/User.ts (2)
1-14
: Clarify the purpose of the "old" directory structure.This file is located in
database/old/entities/
, which suggests it might be deprecated or temporary. If this is intended for production use, consider moving it to the main entities directory. If it's deprecated, consider adding a deprecation comment or removing it entirely.
50-65
: Join column naming is correct and needs no changeThe
joinColumn
/inverseJoinColumn
definitions in both relationships match your SQL migrations and JPA conventions:
- platforms/evoting-api/src/database/old/entities/User.ts (lines 50–56) –
user_followers
table:
• joinColumnuser_id
→ this user’s id
• inverseJoinColumnfollower_id
→ each follower’s id- platforms/evoting-api/src/database/old/entities/User.ts (lines 58–65) –
user_following
table:
• joinColumnuser_id
→ this user’s id
• inverseJoinColumnfollowing_id
→ each followed user’s idNo changes required here.
POSTGRES_USER: evoting | ||
POSTGRES_PASSWORD: evoting | ||
POSTGRES_DB: evoting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Weak default credentials for database.
Using evoting
as both username and password creates a security vulnerability, even in development environments. For an eVoting system, this is particularly concerning.
Consider using environment variables with stronger defaults:
environment:
- POSTGRES_USER: evoting
- POSTGRES_PASSWORD: evoting
- POSTGRES_DB: evoting
+ POSTGRES_USER: ${POSTGRES_USER:-evoting}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-evoting_dev_password_123}
+ POSTGRES_DB: ${POSTGRES_DB:-evoting}
Or add a comment indicating this is for development only:
+ # WARNING: Development only - use strong credentials in production
db:
image: postgres:16
🤖 Prompt for AI Agents
In evoting.compose.yml around lines 6 to 8, the database credentials use weak
default values with POSTGRES_USER and POSTGRES_PASSWORD both set to "evoting".
To fix this, replace these hardcoded credentials with environment variables that
can be set externally to stronger, unique values. Alternatively, add a clear
comment indicating these credentials are for development only and should be
changed in production to improve security.
"dependencies": { | ||
"axios": "^1.6.7", | ||
"better-auth": "^1.3.4", | ||
"cors": "^2.8.5", | ||
"dotenv": "^16.4.5", | ||
"eventsource-polyfill": "^0.9.6", | ||
"express": "^4.18.2", | ||
"graphql-request": "^6.1.0", | ||
"jsonwebtoken": "^9.0.2", | ||
"pg": "^8.11.3", | ||
"reflect-metadata": "^0.2.1", | ||
"typeorm": "^0.3.24", | ||
"uuid": "^9.0.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify dependency versions for security and compatibility.
Several dependencies use caret ranges which could introduce breaking changes or security vulnerabilities. For a production voting system, consider pinning exact versions.
🏁 Script executed:
#!/bin/bash
# Check for known vulnerabilities in the specified dependency versions
npm audit --audit-level moderate --json
Length of output: 630
🌐 Web query:
Are there any known security vulnerabilities in better-auth version 1.3.4, jsonwebtoken version 9.0.2, or express version 4.18.2?
💡 Result:
Based on currently available vulnerability databases and recent security bulletins, here is the status for each specified package and version as of August 2025:
1. better-auth version 1.3.4
No known publicly disclosed security vulnerabilities have been identified for better-auth version 1.3.4 as of June 2025[1][9]. Most known issues, such as open redirect and cross-site scripting (XSS) flaws, affect versions prior to 1.1.21 and 1.1.16, respectively, but not 1.3.4[9]. Review of vulnerability statistics up to 2025 notes two open redirect-related vulnerabilities for the "Better Auth" product overall, but there is no direct evidence that version 1.3.4 is affected by any new or outstanding CVEs[1].
2. jsonwebtoken version 9.0.2
There are no known active vulnerabilities affecting jsonwebtoken version 9.0.2. The critical remote code execution vulnerability (CVE-2022-23529) was fully fixed by version 9.0.0, and no new CVEs have been disclosed for 9.x releases up to 9.0.2[2][6][10]. Previous dependency-related issues (such as a ReDoS vulnerability via [email protected]) are also resolved in 9.0.2[8]. Security monitoring platforms and public advisories consistently report [email protected] as free of known vulnerabilities[4].
3. express version 4.18.2
Express 4.18.2 is affected by at least two known vulnerabilities:
- CVE-2024-29041 (Open Redirect): Express versions prior to 4.19.0 are subject to an open redirect vulnerability in the res.location() and res.redirect() methods, which can be exploited by bypassing URL allow lists via encoded or malformed URLs[3][7]. This flaw is fixed in Express 4.19.2 and later.
- CVE-2024-52798 (as referenced in recent advisories): Additional issues have been flagged in dependency chains associated with Express 4.18.2[7]. The highest-reported severity is 7.5. Upgrading to 4.19.2 or 5.x is recommended[3][7].
In summary:
- [email protected]: No known vulnerabilities as of the latest checks[1][9].
- [email protected]: No known vulnerabilities; safe to use regarding RCE and known dependency issues[2][6][8].
- [email protected]: Vulnerable to multiple known issues (including CVE-2024-29041, Open Redirect); upgrade to ≥4.19.2 is recommended[3][7].
Citations:
- 1: https://www.cvedetails.com/product/177298/Better-auth-Better-Auth.html?vendor_id=36616
- 2: https://unit42.paloaltonetworks.com/jsonwebtoken-vulnerability-cve-2022-23529/
- 3: https://vulners.com/ibm/FB9791B8EE85AD8E00B54CE7DEB5EE6D15E9327012D8E777A4C883CBAAF46168
- 4: https://snyk.io/node-js/jsonwebtoken
- 5: https://blog.doyensec.com/2025/01/30/oauth-common-vulnerabilities.html
- 6: https://heimdalsecurity.com/blog/high-severity-vulnerability-discovered-in-the-jsonwebtoken-library/
- 7: express-4.18.2.tgz: 4 vulnerabilities (highest severity is: 7.5) Nexmo/node-voice-proxy#16
- 8: [email protected] > [email protected] vulnerability mikenicholson/passport-jwt#251
- 9: https://security.snyk.io/package/npm/better-auth/1.1.3-beta.2
- 10: https://www.sentinelone.com/blog/cve-2022-23529/
Upgrade Express to ≥4.19.2 Due to Known Vulnerabilities
Express 4.18.2 is affected by CVE-2024-29041 (open redirect) and other issues; [email protected] and [email protected] have no known CVEs.
• platforms/evoting-api/package.json (Lines 15–27):
– Change
- "express": "^4.18.2"
+ "express": "^4.19.2"
• Add a lockfile (e.g., package-lock.json) and run npm audit
to catch future issues.
• Consider pinning critical dependencies or using an npm shrinkwrap to avoid unintended upgrades.
🤖 Prompt for AI Agents
In platforms/evoting-api/package.json between lines 15 and 27, update the
express dependency version from "^4.18.2" to "^4.19.2" to address known security
vulnerabilities. After updating, generate a lockfile such as package-lock.json
by running npm install, then run npm audit to identify any other issues.
Consider pinning critical dependencies or using npm shrinkwrap to prevent
unintended upgrades in the future.
DROP DATABASE IF EXISTS pic; | ||
CREATE DATABASE pic; | ||
EOF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix inconsistent database name.
The database name pic
doesn't match the eVoting context and appears to be from a different project. Based on the Docker Compose configuration, it should be evoting
.
-DROP DATABASE IF EXISTS pic;
-CREATE DATABASE pic;
+DROP DATABASE IF EXISTS evoting;
+CREATE DATABASE evoting;
📝 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.
DROP DATABASE IF EXISTS pic; | |
CREATE DATABASE pic; | |
EOF | |
DROP DATABASE IF EXISTS evoting; | |
CREATE DATABASE evoting; | |
EOF |
🤖 Prompt for AI Agents
In platforms/evoting-api/reset.sh around lines 8 to 10, the database name used
is `pic`, which is inconsistent with the eVoting project context. Replace all
instances of `pic` with `evoting` to align with the Docker Compose configuration
and project naming conventions.
useEffect(() => { | ||
const logout = async () => { | ||
await authClient.signOut(); | ||
router.push("/login"); | ||
}; | ||
logout(); | ||
}, [router]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling and loading state for better user experience.
The logout process lacks error handling and proper loading states, which could lead to poor user experience.
+import { useState } from "react";
+
export default function LogoutPage() {
const router = useRouter();
+ const [isLoggingOut, setIsLoggingOut] = useState(true);
+ const [error, setError] = useState<string | null>(null);
useEffect(() => {
const logout = async () => {
- await authClient.signOut();
- router.push("/login");
+ try {
+ await authClient.signOut();
+ router.push("/login");
+ } catch (err) {
+ setError("Failed to logout. Please try again.");
+ setIsLoggingOut(false);
+ }
};
logout();
}, [router]);
📝 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.
useEffect(() => { | |
const logout = async () => { | |
await authClient.signOut(); | |
router.push("/login"); | |
}; | |
logout(); | |
}, [router]); | |
import { useState } from "react"; | |
export default function LogoutPage() { | |
const router = useRouter(); | |
const [isLoggingOut, setIsLoggingOut] = useState(true); | |
const [error, setError] = useState<string | null>(null); | |
useEffect(() => { | |
const logout = async () => { | |
try { | |
await authClient.signOut(); | |
router.push("/login"); | |
} catch (err) { | |
setError("Failed to logout. Please try again."); | |
setIsLoggingOut(false); | |
} | |
}; | |
logout(); | |
}, [router]); | |
// ...rest of your component (e.g. render a spinner or error message) | |
} |
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/logout/page.tsx around lines 10 to 16, the
logout function lacks error handling and does not manage a loading state. Add a
loading state variable to indicate when logout is in progress, and wrap the
signOut and router.push calls in a try-catch block to handle potential errors
gracefully. Update the UI or state accordingly to reflect loading and error
conditions for better user experience.
return ( | ||
<div> | ||
<h1>Logout</h1> | ||
<p>You are being logged out.</p> | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve logout UI with proper state feedback.
The current UI doesn't reflect the actual logout state and could be confusing to users.
return (
<div>
<h1>Logout</h1>
- <p>You are being logged out.</p>
+ {error ? (
+ <div>
+ <p style={{ color: 'red' }}>{error}</p>
+ <button onClick={() => router.push("/login")}>
+ Go to Login
+ </button>
+ </div>
+ ) : (
+ <p>You are being logged out...</p>
+ )}
</div>
);
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/logout/page.tsx around lines 18 to 24, the
logout UI lacks feedback on the logout process state, which may confuse users.
Enhance the component to include state management that reflects the logout
progress, such as showing a loading indicator while logging out and a
confirmation message once completed. Use React state or effects to track and
display these states clearly to improve user experience.
const handleSubmit = async () => { | ||
setError(""); | ||
const res = await authClient.signUp.email({ | ||
email, | ||
name: displayName, | ||
password, | ||
}); | ||
if (res.error?.message) { | ||
setError(res.error.message); | ||
return; | ||
} | ||
console.log("Registration successful:", res.data); | ||
router.push("/login"); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add form validation and loading state.
The registration form lacks input validation and loading state management, which could lead to poor user experience and invalid submissions.
+const [isLoading, setIsLoading] = useState(false);
+
+const validateForm = () => {
+ if (!email || !displayName || !password) {
+ setError("All fields are required");
+ return false;
+ }
+ if (!/\S+@\S+\.\S+/.test(email)) {
+ setError("Please enter a valid email address");
+ return false;
+ }
+ if (password.length < 8) {
+ setError("Password must be at least 8 characters long");
+ return false;
+ }
+ return true;
+};
+
const handleSubmit = async () => {
setError("");
+
+ if (!validateForm()) return;
+
+ setIsLoading(true);
const res = await authClient.signUp.email({
email,
name: displayName,
password,
});
+ setIsLoading(false);
+
if (res.error?.message) {
setError(res.error.message);
return;
}
- console.log("Registration successful:", res.data);
router.push("/login");
};
And update the button:
-<Button className="w-full" onClick={handleSubmit}>
+<Button className="w-full" onClick={handleSubmit} disabled={isLoading}>
+ {isLoading ? "Creating Account..." : "Sign Up"}
- Sign Up
</Button>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const handleSubmit = async () => { | |
setError(""); | |
const res = await authClient.signUp.email({ | |
email, | |
name: displayName, | |
password, | |
}); | |
if (res.error?.message) { | |
setError(res.error.message); | |
return; | |
} | |
console.log("Registration successful:", res.data); | |
router.push("/login"); | |
}; | |
// Add loading state and form validation | |
const [isLoading, setIsLoading] = useState(false); | |
const validateForm = () => { | |
if (!email || !displayName || !password) { | |
setError("All fields are required"); | |
return false; | |
} | |
if (!/\S+@\S+\.\S+/.test(email)) { | |
setError("Please enter a valid email address"); | |
return false; | |
} | |
if (password.length < 8) { | |
setError("Password must be at least 8 characters long"); | |
return false; | |
} | |
return true; | |
}; | |
const handleSubmit = async () => { | |
setError(""); | |
if (!validateForm()) return; | |
setIsLoading(true); | |
const res = await authClient.signUp.email({ | |
email, | |
name: displayName, | |
password, | |
}); | |
setIsLoading(false); | |
if (res.error?.message) { | |
setError(res.error.message); | |
return; | |
} | |
router.push("/login"); | |
}; |
const handleSubmit = async () => { | |
setError(""); | |
const res = await authClient.signUp.email({ | |
email, | |
name: displayName, | |
password, | |
}); | |
if (res.error?.message) { | |
setError(res.error.message); | |
return; | |
} | |
console.log("Registration successful:", res.data); | |
router.push("/login"); | |
}; | |
<Button | |
className="w-full" | |
onClick={handleSubmit} | |
disabled={isLoading} | |
> | |
{isLoading ? "Creating Account..." : "Sign Up"} | |
</Button> |
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/register/page.tsx around lines 17 to 30, the
handleSubmit function lacks input validation and loading state management. Add
validation checks for email, displayName, and password before calling signUp to
prevent invalid submissions. Introduce a loading state variable to disable the
submit button and show a loading indicator while the async request is in
progress. Update the submit button to reflect the loading state and prevent
multiple submissions.
setError(res.error.message); | ||
return; | ||
} | ||
console.log("Registration successful:", res.data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove sensitive data from console logs.
Logging registration data to the console could expose sensitive information in production environments.
-console.log("Registration successful:", res.data);
+// Registration successful - redirecting to login
📝 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.
console.log("Registration successful:", res.data); | |
// Registration successful - redirecting to login |
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/register/page.tsx at line 28, remove the
console.log statement that outputs registration data, as it may expose sensitive
information. Instead, either eliminate the log entirely or replace it with a
non-sensitive confirmation message that does not include user data.
export const authClient = createAuthClient({ | ||
/** The base URL of the server (optional if you're using the same domain) */ | ||
baseURL: "http://localhost:4000", | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace hardcoded localhost URL with environment-based configuration.
The hardcoded baseURL: "http://localhost:4000"
will break in production and other environments.
-export const authClient = createAuthClient({
- /** The base URL of the server (optional if you're using the same domain) */
- baseURL: "http://localhost:4000",
-});
+export const authClient = createAuthClient({
+ /** The base URL of the server (optional if you're using the same domain) */
+ baseURL: process.env.NEXT_PUBLIC_AUTH_BASE_URL || "http://localhost:4000",
+});
Add NEXT_PUBLIC_AUTH_BASE_URL
to your environment configuration files for different deployment environments.
📝 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.
export const authClient = createAuthClient({ | |
/** The base URL of the server (optional if you're using the same domain) */ | |
baseURL: "http://localhost:4000", | |
}); | |
export const authClient = createAuthClient({ | |
/** The base URL of the server (optional if you're using the same domain) */ | |
baseURL: process.env.NEXT_PUBLIC_AUTH_BASE_URL || "http://localhost:4000", | |
}); |
🤖 Prompt for AI Agents
In platforms/eVoting/src/lib/auth-client.ts around lines 2 to 5, the baseURL is
hardcoded to "http://localhost:4000", which will fail in production or other
environments. Replace the hardcoded URL with a reference to an environment
variable, such as process.env.NEXT_PUBLIC_AUTH_BASE_URL, to dynamically set the
baseURL based on the deployment environment. Ensure that
NEXT_PUBLIC_AUTH_BASE_URL is added to the environment configuration files for
all relevant environments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review continued from previous batch...
constructor(dbPath) { | ||
// Ensure the directory exists | ||
const fullPath = (0, node_path_1.join)(dbPath, "mappings.db"); | ||
this.db = new sqlite3_1.default.Database(fullPath); | ||
// Promisify database methods | ||
this.runAsync = (0, node_util_1.promisify)(this.db.run.bind(this.db)); | ||
this.getAsync = (0, node_util_1.promisify)(this.db.get.bind(this.db)); | ||
this.allAsync = (0, node_util_1.promisify)(this.db.all.bind(this.db)); | ||
// Initialize the database with the required tables | ||
this.initialize(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Async initialization in constructor and missing directory creation
The constructor has several issues:
- The comment says "Ensure the directory exists" but no directory creation logic is present
initialize()
is an async method but called without await in the constructor, which could lead to race conditions- No validation of the
dbPath
parameter
Apply this fix:
- constructor(dbPath) {
- // Ensure the directory exists
- const fullPath = (0, node_path_1.join)(dbPath, "mappings.db");
- this.db = new sqlite3_1.default.Database(fullPath);
+ constructor(dbPath) {
+ if (!dbPath) {
+ throw new Error("dbPath is required");
+ }
+ this.dbPath = dbPath;
+ this.db = null;
// Promisify database methods
- this.runAsync = (0, node_util_1.promisify)(this.db.run.bind(this.db));
- this.getAsync = (0, node_util_1.promisify)(this.db.get.bind(this.db));
- this.allAsync = (0, node_util_1.promisify)(this.db.all.bind(this.db));
- // Initialize the database with the required tables
- this.initialize();
+ this.runAsync = null;
+ this.getAsync = null;
+ this.allAsync = null;
}
+
+ async ensureInitialized() {
+ if (this.db) return;
+
+ const fs = require('node:fs/promises');
+ const path = require('node:path');
+
+ // Ensure the directory exists
+ await fs.mkdir(this.dbPath, { recursive: true });
+
+ const fullPath = path.join(this.dbPath, "mappings.db");
+ this.db = new sqlite3_1.default.Database(fullPath);
+
+ // Promisify database methods
+ this.runAsync = (0, node_util_1.promisify)(this.db.run.bind(this.db));
+ this.getAsync = (0, node_util_1.promisify)(this.db.get.bind(this.db));
+ this.allAsync = (0, node_util_1.promisify)(this.db.all.bind(this.db));
+
+ // Initialize the database with the required tables
+ await this.initialize();
+ }
Then ensure all public methods call await this.ensureInitialized()
at the start.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js around lines 11 to 21, the
constructor lacks directory creation for the database path, calls the async
initialize() method without awaiting it, and does not validate the dbPath
parameter. Fix this by first validating dbPath to ensure it is a non-empty
string, then create the directory if it does not exist before opening the
database. Change initialize() to be awaited properly by moving async
initialization outside the constructor or by adding an internal flag and an
ensureInitialized() method that public methods can await before proceeding.
Update all public methods to call await this.ensureInitialized() at their start
to avoid race conditions.
async storeMapping(params) { | ||
// Validate inputs | ||
if (!params.localId || !params.globalId) { | ||
throw new Error("Invalid mapping parameters: all fields are required"); | ||
} | ||
console.log("storing mapping g:l", params.globalId, params.localId); | ||
// Check if mapping already exists | ||
const existingMapping = await this.getGlobalId(params.localId); | ||
if (existingMapping) { | ||
return; | ||
} | ||
await this.runAsync(`INSERT INTO id_mappings (local_id, global_id) | ||
VALUES (?, ?)`, [params.localId, params.globalId]); | ||
const storedMapping = await this.getGlobalId(params.localId); | ||
if (storedMapping !== params.globalId) { | ||
console.log("storedMappingError", storedMapping, params.globalId); | ||
console.error("Failed to store mapping"); | ||
return; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Race condition and silent failures in storeMapping
Several issues with this method:
- Race condition between checking existence and inserting
- Silent return when mapping exists (no indication to caller)
- Debug console.log statements should be removed
- Inefficient verification after insert
Consider using INSERT OR IGNORE and checking affected rows:
async storeMapping(params) {
// Validate inputs
if (!params.localId || !params.globalId) {
throw new Error("Invalid mapping parameters: all fields are required");
}
- console.log("storing mapping g:l", params.globalId, params.localId);
- // Check if mapping already exists
- const existingMapping = await this.getGlobalId(params.localId);
- if (existingMapping) {
- return;
- }
- await this.runAsync(`INSERT INTO id_mappings (local_id, global_id)
- VALUES (?, ?)`, [params.localId, params.globalId]);
- const storedMapping = await this.getGlobalId(params.localId);
- if (storedMapping !== params.globalId) {
- console.log("storedMappingError", storedMapping, params.globalId);
- console.error("Failed to store mapping");
- return;
- }
+
+ const result = await this.runAsync(
+ `INSERT OR IGNORE INTO id_mappings (local_id, global_id) VALUES (?, ?)`,
+ [params.localId, params.globalId]
+ );
+
+ if (result.changes === 0) {
+ // Mapping already exists, check if it's the same
+ const existing = await this.getGlobalId(params.localId);
+ if (existing !== params.globalId) {
+ throw new Error(`Mapping conflict: localId ${params.localId} already mapped to ${existing}`);
+ }
+ }
}
📝 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.
async storeMapping(params) { | |
// Validate inputs | |
if (!params.localId || !params.globalId) { | |
throw new Error("Invalid mapping parameters: all fields are required"); | |
} | |
console.log("storing mapping g:l", params.globalId, params.localId); | |
// Check if mapping already exists | |
const existingMapping = await this.getGlobalId(params.localId); | |
if (existingMapping) { | |
return; | |
} | |
await this.runAsync(`INSERT INTO id_mappings (local_id, global_id) | |
VALUES (?, ?)`, [params.localId, params.globalId]); | |
const storedMapping = await this.getGlobalId(params.localId); | |
if (storedMapping !== params.globalId) { | |
console.log("storedMappingError", storedMapping, params.globalId); | |
console.error("Failed to store mapping"); | |
return; | |
} | |
} | |
async storeMapping(params) { | |
// Validate inputs | |
if (!params.localId || !params.globalId) { | |
throw new Error("Invalid mapping parameters: all fields are required"); | |
} | |
const result = await this.runAsync( | |
`INSERT OR IGNORE INTO id_mappings (local_id, global_id) VALUES (?, ?)`, | |
[params.localId, params.globalId] | |
); | |
if (result.changes === 0) { | |
// Mapping already exists, check if it's the same | |
const existing = await this.getGlobalId(params.localId); | |
if (existing !== params.globalId) { | |
throw new Error( | |
`Mapping conflict: localId ${params.localId} already mapped to ${existing}` | |
); | |
} | |
} | |
} |
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js lines 38 to 57, fix the race
condition by replacing the existence check and insert with a single atomic
operation using "INSERT OR IGNORE" to avoid duplicate entries. Remove all
console.log debug statements. Instead of verifying the insert by querying again,
check the number of affected rows returned by the insert operation to confirm
success. Also, modify the method to return a clear indication (e.g., a boolean)
whether the mapping was stored or already existed, avoiding silent returns.
async getGlobalId(localId) { | ||
if (!localId) { | ||
return null; | ||
} | ||
try { | ||
const result = await this.getAsync(`SELECT global_id | ||
FROM id_mappings | ||
WHERE local_id = ?`, [localId]); | ||
return result?.global_id ?? null; | ||
} | ||
catch (error) { | ||
console.error("Error getting global ID:", error); | ||
return null; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve error handling to distinguish between not found and database errors
The current implementation swallows errors and returns null, making it impossible to distinguish between a missing mapping and a database error.
async getGlobalId(localId) {
if (!localId) {
return null;
}
- try {
- const result = await this.getAsync(`SELECT global_id
- FROM id_mappings
- WHERE local_id = ?`, [localId]);
- return result?.global_id ?? null;
- }
- catch (error) {
- console.error("Error getting global ID:", error);
- return null;
- }
+ const result = await this.getAsync(
+ `SELECT global_id FROM id_mappings WHERE local_id = ?`,
+ [localId]
+ );
+ return result?.global_id ?? null;
}
Let errors propagate to the caller for proper handling.
📝 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.
async getGlobalId(localId) { | |
if (!localId) { | |
return null; | |
} | |
try { | |
const result = await this.getAsync(`SELECT global_id | |
FROM id_mappings | |
WHERE local_id = ?`, [localId]); | |
return result?.global_id ?? null; | |
} | |
catch (error) { | |
console.error("Error getting global ID:", error); | |
return null; | |
} | |
} | |
async getGlobalId(localId) { | |
if (!localId) { | |
return null; | |
} | |
const result = await this.getAsync( | |
`SELECT global_id FROM id_mappings WHERE local_id = ?`, | |
[localId] | |
); | |
return result?.global_id ?? null; | |
} |
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js around lines 61 to 75, the
getGlobalId method currently catches all errors and returns null, which hides
the difference between a missing record and a database error. Remove the
try-catch block so that database errors propagate to the caller, while still
returning null when no mapping is found by checking if the query result is
empty.
async getLocalId(globalId) { | ||
if (!globalId) { | ||
return null; | ||
} | ||
try { | ||
const result = await this.getAsync(`SELECT local_id | ||
FROM id_mappings | ||
WHERE global_id = ?`, [globalId]); | ||
return result?.local_id ?? null; | ||
} | ||
catch (error) { | ||
return null; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove error suppression for consistent error handling
Similar to getGlobalId
, this method suppresses errors which prevents proper error handling.
async getLocalId(globalId) {
if (!globalId) {
return null;
}
- try {
- const result = await this.getAsync(`SELECT local_id
- FROM id_mappings
- WHERE global_id = ?`, [globalId]);
- return result?.local_id ?? null;
- }
- catch (error) {
- return null;
- }
+ const result = await this.getAsync(
+ `SELECT local_id FROM id_mappings WHERE global_id = ?`,
+ [globalId]
+ );
+ return result?.local_id ?? null;
}
📝 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.
async getLocalId(globalId) { | |
if (!globalId) { | |
return null; | |
} | |
try { | |
const result = await this.getAsync(`SELECT local_id | |
FROM id_mappings | |
WHERE global_id = ?`, [globalId]); | |
return result?.local_id ?? null; | |
} | |
catch (error) { | |
return null; | |
} | |
} | |
async getLocalId(globalId) { | |
if (!globalId) { | |
return null; | |
} | |
const result = await this.getAsync( | |
`SELECT local_id FROM id_mappings WHERE global_id = ?`, | |
[globalId] | |
); | |
return result?.local_id ?? null; | |
} |
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js around lines 79 to 92, the
getLocalId method currently suppresses errors by catching them and returning
null, which prevents consistent error handling. Remove the try-catch block so
that any errors thrown during the database query propagate naturally, allowing
callers to handle them properly, similar to the getGlobalId method.
close() { | ||
try { | ||
this.db.close(); | ||
} | ||
catch (error) { | ||
console.error("Error closing database connection:", error); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve database closure handling
The close method needs improvements:
- Should check if already closed
- Should nullify the db reference
- Remove console.error
close() {
- try {
- this.db.close();
- }
- catch (error) {
- console.error("Error closing database connection:", error);
- }
+ if (this.db) {
+ this.db.close((err) => {
+ if (err) {
+ throw new Error(`Failed to close database: ${err.message}`);
+ }
+ });
+ this.db = null;
+ this.runAsync = null;
+ this.getAsync = null;
+ this.allAsync = null;
+ }
}
📝 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.
close() { | |
try { | |
this.db.close(); | |
} | |
catch (error) { | |
console.error("Error closing database connection:", error); | |
} | |
} | |
close() { | |
if (this.db) { | |
this.db.close((err) => { | |
if (err) { | |
throw new Error(`Failed to close database: ${err.message}`); | |
} | |
}); | |
this.db = null; | |
this.runAsync = null; | |
this.getAsync = null; | |
this.allAsync = null; | |
} | |
} |
🤖 Prompt for AI Agents
In infrastructure/web3-adapter/src/db/mapping.db.js around lines 122 to 129,
improve the close method by first checking if the database connection is already
closed before attempting to close it, then after closing, set the db reference
to null to avoid stale references, and replace the console.error with proper
error handling or logging mechanism as per project standards.
if (res.error?.message) { | ||
console.error("Login failed:", res.error.message); | ||
return; | ||
} | ||
console.log("Login successful:", res.data); | ||
router.push("/"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove console logging of authentication data.
Logging authentication responses to console poses a security risk as it may expose sensitive user data or tokens.
- if (res.error?.message) {
- console.error("Login failed:", res.error.message);
- return;
- }
- console.log("Login successful:", res.data);
+ if (res.error?.message) {
+ // TODO: Show user-friendly error message
+ return;
+ }
📝 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.
if (res.error?.message) { | |
console.error("Login failed:", res.error.message); | |
return; | |
} | |
console.log("Login successful:", res.data); | |
router.push("/"); | |
if (res.error?.message) { | |
// TODO: Show user-friendly error message | |
return; | |
} | |
router.push("/"); |
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/login/page.tsx between lines 21 and 26,
remove all console logging statements that output authentication response data,
including both error and success logs, to prevent exposing sensitive user
information. Replace these logs with appropriate user feedback mechanisms or
silent handling without printing authentication details to the console.
<div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap"> | ||
<span>Scan the QR using your</span> | ||
<span className="font-bold underline">eID App</span> | ||
<span>to login</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
UI text inconsistency with actual authentication method.
The UI mentions "Scan the QR using your eID App" but the actual implementation uses email/password authentication. This creates user confusion.
Either implement QR/eID authentication or update the UI text to match the email/password flow:
- <div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
- <span>Scan the QR using your</span>
- <span className="font-bold underline">eID App</span>
- <span>to login</span>
- </div>
+ <div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap">
+ <span>Enter your credentials to login</span>
+ </div>
📝 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.
<div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap"> | |
<span>Scan the QR using your</span> | |
<span className="font-bold underline">eID App</span> | |
<span>to login</span> | |
<div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap"> | |
<span>Enter your credentials to login</span> | |
</div> |
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/login/page.tsx around lines 42 to 45, the UI
text incorrectly instructs users to scan a QR code with the eID App, while the
actual authentication method is email/password. To fix this, update the UI text
to clearly describe the email/password login process instead of mentioning QR
code scanning or the eID App, ensuring the displayed instructions match the
implemented authentication flow.
<Input | ||
placeholder="Email" | ||
value={email} | ||
onChange={(e) => setEmail(e.target.value)} | ||
type="text" | ||
/> | ||
<Input | ||
placeholder="password" | ||
value={password} | ||
onChange={(e) => setPassword(e.target.value)} | ||
type="password" | ||
/> | ||
<Button onClick={handleSubmit}>Submit</Button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add input validation and improve error handling.
The form lacks client-side validation and proper error feedback to users.
+ const [error, setError] = useState("");
+ const [isLoading, setIsLoading] = useState(false);
+
const handleSubmit = async () => {
+ setError("");
+
+ if (!email || !password) {
+ setError("Please enter both email and password");
+ return;
+ }
+
+ setIsLoading(true);
const res = await authClient.signIn.email({
email,
password,
});
+ setIsLoading(false);
+
if (res.error?.message) {
+ setError(res.error.message);
return;
}
router.push("/");
};
Add error display in the JSX:
+ {error && (
+ <div className="text-red-500 text-sm">{error}</div>
+ )}
<Input
📝 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.
<Input | |
placeholder="Email" | |
value={email} | |
onChange={(e) => setEmail(e.target.value)} | |
type="text" | |
/> | |
<Input | |
placeholder="password" | |
value={password} | |
onChange={(e) => setPassword(e.target.value)} | |
type="password" | |
/> | |
<Button onClick={handleSubmit}>Submit</Button> | |
// --- at the top of your component, alongside the existing useState hooks: | |
const [error, setError] = useState(""); | |
const [isLoading, setIsLoading] = useState(false); | |
const handleSubmit = async () => { | |
setError(""); | |
if (!email || !password) { | |
setError("Please enter both email and password"); | |
return; | |
} | |
setIsLoading(true); | |
const res = await authClient.signIn.email({ | |
email, | |
password, | |
}); | |
setIsLoading(false); | |
if (res.error?.message) { | |
setError(res.error.message); | |
return; | |
} | |
router.push("/"); | |
}; | |
return ( | |
<div> | |
{/* error message */} | |
{error && ( | |
<div className="text-red-500 text-sm">{error}</div> | |
)} | |
<Input | |
placeholder="Email" | |
value={email} | |
onChange={(e) => setEmail(e.target.value)} | |
type="text" | |
/> | |
<Input | |
placeholder="password" | |
value={password} | |
onChange={(e) => setPassword(e.target.value)} | |
type="password" | |
/> | |
<Button onClick={handleSubmit}> | |
Submit | |
</Button> | |
</div> | |
); |
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/login/page.tsx around lines 58 to 70, the
input fields lack client-side validation and there is no error feedback shown to
users. Add validation logic to check the email format and password requirements
before submission. Implement state to track validation errors and display
appropriate error messages in the JSX near the inputs. Also, update the
handleSubmit function to prevent submission if validation fails and show
relevant error feedback to the user.
// const { isAuthenticated, user } = useAuth(); | ||
const isAuthenticated = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove hardcoded authentication status
The isAuthenticated
variable is hardcoded to true
, which bypasses the actual authentication check from the session. This could expose authenticated UI to unauthenticated users.
- // const { isAuthenticated, user } = useAuth();
- const isAuthenticated = true;
+ const session = authClient.useSession();
+ const isAuthenticated = !!session.data?.user;
Then update line 40 to remove the duplicate session declaration:
- const session = authClient.useSession();
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// const { isAuthenticated, user } = useAuth(); | |
const isAuthenticated = true; | |
// Replace the hardcoded auth flag with a real session check | |
- // const { isAuthenticated, user } = useAuth(); | |
- const isAuthenticated = true; | |
+ const session = authClient.useSession(); | |
+ const isAuthenticated = !!session.data?.user; | |
// … later in the file, remove the duplicate declaration | |
// (drop this line) | |
// const session = authClient.useSession(); |
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/navigation.tsx around lines 31 to 32, remove
the hardcoded assignment of isAuthenticated to true and uncomment the original
line that destructures isAuthenticated and user from useAuth(). Then, at line
40, remove the duplicate session declaration to avoid redundancy and potential
conflicts.
{session.data?.user?.name || | ||
session.data?.user?.email || | ||
"User"} | ||
username |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove stray "username" text
There's a stray "username" text that will be rendered in the UI.
{session.data?.user?.name ||
session.data?.user?.email ||
"User"}
- username
📝 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.
username | |
{session.data?.user?.name || | |
session.data?.user?.email || | |
"User"} |
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/navigation.tsx at line 212, there is a stray
"username" text that will be rendered unintentionally in the UI. Remove this
standalone "username" text from the JSX to prevent it from appearing in the
rendered output.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (4)
platforms/evoting-api/src/controllers/poll.controller.ts (1)
16-44
: Missing authentication validation in createPoll.The method doesn't validate that the user is authenticated before creating a poll. The service expects a userId parameter, but if
req.user
is undefined, the poll will be created without an owner.Add authentication check:
async createPoll(req: Request, res: Response) { + if (!req.user || !req.user.id) { + return res.status(401).json({ error: "Authentication required" }); + } + const { title, mode, visibility, options, deadline } = req.body;Note: The parameter passing issue from the previous review has been correctly addressed - the controller now properly destructures the request body and passes individual parameters to the service.
platforms/evoting-api/src/services/poll.service.ts (3)
11-33
: Inconsistent rank vote validation between type guard and inline validation.The
isValidRankVote
function validates data as an array of objects withoption
andpoints
properties (matching theRankVoteData
type), but the inline validation incastVote
(lines 148-158) expects an array of strings. This inconsistency will cause runtime errors.Either update the inline validation to match the type guard:
case "rank": - if ( - !Array.isArray(data) || - data.length !== poll.options.length || - data.some((d) => typeof d !== "string") || - new Set(data).size !== data.length || - data.some((option) => !poll.options.includes(option)) - ) { + if (!isValidRankVote(data, poll.options)) { throw new Error("Invalid vote for rank mode"); } break;Or update both the type and validation function to use string arrays if that's the intended format.
Also applies to: 148-158
89-94
: Privacy concern: Votes are included when fetching polls.Including votes in poll queries could expose voting data inappropriately. Consider whether votes should be visible and to whom.
Remove votes from default queries:
async getPolls(visibility?: "public" | "private"): Promise<Poll[]> { return this.pollRepository.find({ where: visibility ? { visibility } : {}, - relations: ["votes"], }); }
Similarly for
getPollById
:async getPollById(pollId: string): Promise<Poll | null> { return await this.pollRepository.findOne({ where: { id: pollId }, - relations: ["votes"], }); }
Add a separate method to get poll results when appropriate with proper authorization.
134-146
: Use validation function instead of inline validation for point mode.The inline validation duplicates the logic in
isValidPointVote
function, creating maintenance issues.Replace with the validation function:
case "point": - if ( - !Array.isArray(data) || - data.length === 0 || - data.some( - (d) => - typeof d.option !== "string" || - typeof d.points !== "number" || - !poll.options.includes(d.option), - ) - ) { + if (!isValidPointVote(data, poll.options)) { throw new Error("Invalid vote for point mode"); } break;
🧹 Nitpick comments (1)
platforms/evoting-api/src/controllers/poll.controller.ts (1)
76-92
: Consider extracting normal mode validation for consistency.While the validation logic is correct, normal mode uses inline validation while point and rank modes use imported functions. For consistency and reusability, consider creating an
isValidNormalVote
function.Add to poll.service.ts:
export function isValidNormalVote( data: unknown, pollOptions: string[], ): data is string[] { return ( Array.isArray(data) && data.length > 0 && data.every(d => typeof d === "string" && pollOptions.includes(d)) ); }Then update the controller:
-if (poll.mode === "normal" && !Array.isArray(data)) { +if (poll.mode === "normal" && !isValidNormalVote(data, pollOptions)) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
platforms/evoting-api/src/controllers/poll.controller.ts
(1 hunks)platforms/evoting-api/src/services/poll.service.ts
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
platforms/evoting-api/src/controllers/poll.controller.ts (1)
platforms/evoting-api/src/services/poll.service.ts (3)
PollService
(52-200)isValidPointVote
(35-50)isValidRankVote
(11-33)
platforms/evoting-api/src/services/poll.service.ts (2)
platforms/evoting-api/src/database/entities/Vote.ts (3)
RankVoteData
(19-22)PointVoteData
(14-17)VoteDataByMode
(26-29)platforms/eVoting/src/app/(app)/[id]/page.tsx (1)
Vote
(23-573)
🔇 Additional comments (2)
platforms/evoting-api/src/controllers/poll.controller.ts (1)
65-67
: Good authentication validation!The authentication check is properly implemented here, ensuring only authenticated users can cast votes.
platforms/evoting-api/src/services/poll.service.ts (1)
35-50
: Well-implemented point vote validation.The validation function correctly checks for array structure, uniqueness of options, and proper types.
async getPoll(req: Request, res: Response) { | ||
try { | ||
const poll = await this.pollService.getPollById(req.params.id); | ||
if (!poll) return res.status(404).json({ error: "Poll not found" }); | ||
res.json(poll); | ||
} catch (err: unknown) { | ||
res.status(500).json({ error: (err as Error).message }); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Consider authorization for private polls.
The method retrieves any poll without checking if the user has permission to view it. Private polls might need authorization checks.
🏁 Script executed:
#!/bin/bash
# Check if Poll entity has visibility-related fields or owner information
ast-grep --pattern 'class Poll {
$$$
}'
Length of output: 2833
🏁 Script executed:
#!/bin/bash
# Locate the implementation of getPollById in PollService
rg "getPollById" -A10 -n platforms/evoting-api/src
Length of output: 6013
Enforce authorization on private polls
getPoll
currently returns any poll—including those marked "private"
—without checking who’s requesting it, and the Poll
entity has no owner or ACL to enforce restrictions. To prevent unauthorized access:
• platforms/evoting-api/src/database/entities/Poll.ts
– Add an owner relation (e.g. @ManyToOne(() => User, user => user.polls) owner: User
)
• platforms/evoting-api/src/services/poll.service.ts (or create a new method)
– When loading a private poll, verify that the current user is the owner (throw a 403 if not)
• platforms/evoting-api/src/controllers/poll.controller.ts#getPoll
– After calling getPollById
, check poll.visibility === "private"
and enforce the owner check before calling res.json
Implementing these changes will ensure private polls remain accessible only to their creators.
🤖 Prompt for AI Agents
In platforms/evoting-api/src/controllers/poll.controller.ts around lines 46 to
54, the getPoll method returns private polls without authorization checks. To
fix this, first update platforms/evoting-api/src/database/entities/Poll.ts to
add an owner relation linking Poll to User. Then, in
platforms/evoting-api/src/services/poll.service.ts, modify or add a method to
verify that if a poll is private, the requesting user is the owner, throwing a
403 error if not authorized. Finally, in getPoll, after retrieving the poll,
check if poll.visibility is "private" and enforce the ownership check before
sending the response, returning a 403 status if the user is not the owner.
async castVote( | ||
pollId: string, | ||
userId: string, | ||
data: VoteDataByMode, // should be validated before calling | ||
): Promise<Vote> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type mismatch in castVote parameter.
The data
parameter is typed as VoteDataByMode
which expects {mode, data}
structure, but the method actually receives and validates just the data portion (string[], PointVoteData, or RankVoteData).
Update the type to match actual usage:
async castVote(
pollId: string,
userId: string,
- data: VoteDataByMode, // should be validated before calling
+ data: string[] | PointVoteData | RankVoteData,
): Promise<Vote> {
📝 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.
async castVote( | |
pollId: string, | |
userId: string, | |
data: VoteDataByMode, // should be validated before calling | |
): Promise<Vote> { | |
async castVote( | |
pollId: string, | |
userId: string, | |
data: string[] | PointVoteData | RankVoteData, | |
): Promise<Vote> { |
🤖 Prompt for AI Agents
In platforms/evoting-api/src/services/poll.service.ts around lines 97 to 101,
the castVote method's data parameter is incorrectly typed as VoteDataByMode,
which expects an object with mode and data properties, but the method actually
receives only the data portion (string[], PointVoteData, or RankVoteData).
Change the type of the data parameter to accept only the data portion types
directly, matching the actual input and validation logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (3)
platforms/eVoting/src/app/(auth)/login/page.tsx (3)
23-27
: Remove console logging of authentication dataLogging authentication responses poses a security risk as it may expose sensitive tokens or user data in production.
- if (res.error?.message) { - console.error("Login failed:", res.error.message); - setError(res.error.message); - return; - } - console.log("Login successful:", res.data); + if (res.error?.message) { + setError(res.error.message); + return; + }
44-47
: UI text doesn't match authentication implementationThe UI mentions "Scan the QR using your eID App" but the actual implementation uses email/password authentication.
- <div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap"> - <span>Scan the QR using your</span> - <span className="font-bold underline">eID App</span> - <span>to login</span> - </div> + <div className="flex justify-center items-center text-xl space-x-1 whitespace-nowrap"> + <span>Enter your credentials to login</span> + </div>
17-29
: Add input validation and loading stateThe form lacks client-side validation and loading feedback during authentication.
+ const [isLoading, setIsLoading] = useState(false); + const handleSubmit = async () => { + if (!email || !password) { + setError("Please enter both email and password"); + return; + } + setIsLoading(true); const res = await authClient.signIn.email({ email, password, }); + setIsLoading(false); if (res.error?.message) { setError(res.error.message); return; } router.push("/"); };And update the button:
- <Button onClick={handleSubmit}>Submit</Button> + <Button onClick={handleSubmit} disabled={isLoading}> + {isLoading ? "Signing in..." : "Submit"} + </Button>Also applies to: 65-77
🧹 Nitpick comments (3)
platforms/eVoting/src/app/(auth)/login/page.tsx (1)
72-72
: Capitalize password placeholder for consistencyThe password placeholder should be capitalized to match the email field.
- placeholder="password" + placeholder="Password"platforms/eVoting/src/app/(app)/layout.tsx (2)
102-104
: Simplify empty return statementUse
null
instead of empty fragment for cleaner code.- ) : ( - <></> - )} + ) : null}
74-77
: Remove duplicate disclaimer textThe disclaimer contains redundant text about the app being in development.
<p> - The app is still in development, so we - kindly ask for your understanding - regarding any potential issues. If you + If you experience issues or have feedback, feel free to contact us at: </p>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
platforms/eVoting/package.json
(1 hunks)platforms/eVoting/src/app/(app)/layout.tsx
(1 hunks)platforms/eVoting/src/app/(auth)/login/page.tsx
(1 hunks)platforms/eVoting/src/app/(auth)/register/page.tsx
(1 hunks)platforms/eVoting/src/components/ui/dialog.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- platforms/eVoting/package.json
- platforms/eVoting/src/app/(auth)/register/page.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-06-07T04:59:24.520Z
Learnt from: Sahil2004
PR: MetaState-Prototype-Project/prototype#193
File: platforms/metagram/src/lib/store/store.svelte.ts:0-0
Timestamp: 2025-06-07T04:59:24.520Z
Learning: In the MetaState prototype project, prefer using centralized type definitions from `$lib/types` over importing interfaces from component files for better type organization and to avoid circular dependencies.
Applied to files:
platforms/eVoting/src/components/ui/dialog.tsx
📚 Learning: 2025-04-16T18:04:28.983Z
Learnt from: coodos
PR: MetaState-Prototype-Project/prototype#99
File: infrastructure/w3id/tests/w3id.test.ts:48-57
Timestamp: 2025-04-16T18:04:28.983Z
Learning: In test files, suggestions to add defensive coding patterns (like extra null checks) are often unnecessary, as tests are designed to fail explicitly when expectations aren't met. The test in `infrastructure/w3id/tests/w3id.test.ts` validates that `id.logs` is an instance of `IDLogManager` before accessing its repository property.
Applied to files:
platforms/eVoting/src/app/(auth)/login/page.tsx
🧬 Code Graph Analysis (2)
platforms/eVoting/src/components/ui/dialog.tsx (1)
infrastructure/eid-wallet/src/lib/utils/mergeClasses.ts (1)
cn
(4-6)
platforms/eVoting/src/app/(auth)/login/page.tsx (3)
platforms/eVoting/src/lib/auth-client.ts (1)
authClient
(2-5)platforms/eVoting/src/components/ui/card.tsx (2)
Card
(80-80)CardHeader
(81-81)platforms/blabsy/src/components/input/input.tsx (1)
Input
(43-290)
🔇 Additional comments (1)
platforms/eVoting/src/app/(app)/layout.tsx (1)
22-33
: Good authentication state handlingThe session management correctly handles loading states and redirects unauthenticated users.
<Dialog open> | ||
<DialogContent | ||
className="max-w-lg mx-auto backdrop-blur-md p-6 rounded-lg" | ||
onInteractOutside={() => router.push("/logout")} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Reconsider aggressive logout on outside interaction
Logging out users when they click outside the disclaimer dialog may be too harsh. Users might accidentally click outside while reading.
Consider warning users first or removing this behavior:
- onInteractOutside={() => router.push("/logout")}
+ onInteractOutside={(e) => {
+ e.preventDefault();
+ // Optionally show a warning that they must accept to continue
+ }}
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(app)/layout.tsx at line 43, the current code logs
out users immediately when they click outside the disclaimer dialog, which can
be too aggressive. Modify this behavior to either show a warning or confirmation
prompt before logging out, or remove the automatic logout on outside interaction
entirely to prevent accidental logouts.
<p className="font-bold text-md"> | ||
The code is only valid for 60 seconds | ||
</p> | ||
<p>Please refresh the page if it expires</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove misleading expiry message
The message about code validity doesn't apply to email/password authentication.
- <span className="flex flex-col gap-2 items-center">
- <p className="font-bold text-md">
- The code is only valid for 60 seconds
- </p>
- <p>Please refresh the page if it expires</p>
- </span>
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In platforms/eVoting/src/app/(auth)/login/page.tsx around lines 86 to 89, remove
the paragraph elements that state "The code is only valid for 60 seconds" and
"Please refresh the page if it expires" because these messages are misleading
for email/password authentication. Simply delete these lines to avoid confusion.
const DialogContent = React.forwardRef< | ||
React.ElementRef<typeof DialogPrimitive.Content>, | ||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> | ||
React.ElementRef<typeof DialogPrimitive.Content>, | ||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> | ||
>(({ className, children, ...props }, ref) => ( | ||
<DialogPortal> | ||
<DialogOverlay /> | ||
<DialogPrimitive.Content | ||
ref={ref} | ||
className={cn( | ||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", | ||
className | ||
)} | ||
{...props} | ||
> | ||
{children} | ||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> | ||
<X className="h-4 w-4" /> | ||
<span className="sr-only">Close</span> | ||
</DialogPrimitive.Close> | ||
</DialogPrimitive.Content> | ||
</DialogPortal> | ||
)) | ||
DialogContent.displayName = DialogPrimitive.Content.displayName | ||
<DialogPortal> | ||
<DialogOverlay /> | ||
<DialogPrimitive.Content | ||
ref={ref} | ||
className={cn( | ||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", | ||
className | ||
)} | ||
{...props} | ||
> | ||
{children} | ||
</DialogPrimitive.Content> | ||
</DialogPortal> | ||
)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Missing close button may impact user experience
The DialogContent
component no longer includes a close button (X icon), which was previously present. This removal means users cannot easily dismiss dialogs unless the parent component provides an alternative closing mechanism.
Consider either:
- Re-adding the close button for better UX
- Ensuring all dialog implementations provide clear dismissal options
🏁 Script executed:
#!/bin/bash
# Description: Check how dialogs are being used and if they have alternative close mechanisms
# Search for Dialog usage to verify if close mechanisms are provided
rg -A 10 "DialogContent" --glob "*.tsx" --glob "*.jsx" | head -50
# Check if DialogClose is being used elsewhere
rg "DialogClose" --glob "*.tsx" --glob "*.jsx"
Length of output: 5251
🏁 Script executed:
#!/bin/bash
set -e
echo "Displaying the first 200 lines of the file:"
sed -n '1,200p' platforms/eVoting/src/components/ui/dialog.tsx
Length of output: 3860
🏁 Script executed:
#!/bin/bash
# Check for explicit DialogClose usage in group-charter-manager page
rg "<DialogClose" --glob "platforms/group-charter-manager/src/app/charter/[id]/*.tsx"
Length of output: 236
🏁 Script executed:
#!/bin/bash
# Search for actual usage of <DialogClose> in group-charter-manager pages to confirm if consumers add close buttons
rg "<DialogClose" platforms/group-charter-manager/src/app
Length of output: 59
Ensure dialogs include a clear close control
The base DialogContent
no longer renders a default “X” close button, so none of your dialogs show a dismissal control unless every consumer adds <DialogClose>
manually. We audited the usages (e.g. in platforms/group-charter-manager/src/app/charter/[id]/page.tsx
) and found no <DialogClose>
instances.
To restore an accessible, discoverable close action, choose one of the following:
- Re-introduce a built-in close button in
DialogContent
(e.g. at the top-right corner):<DialogPrimitive.Content …> <DialogClose asChild className="absolute top-4 right-4"> <button aria-label="Close"><X /></button> </DialogClose> {children} </DialogPrimitive.Content>
- Or update every dialog usage to include
<DialogClose>
in its markup and ensure it’s styled/positioned consistently.
Files needing attention:
- platforms/eVoting/src/components/ui/dialog.tsx → wrap
<DialogPrimitive.Content>
children with a default<DialogClose>
or document the requirement. - Downstream usages (e.g.
platforms/group-charter-manager/src/app/charter/[id]/page.tsx
) → add<DialogClose>
if you opt to keep it opt-in.
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/ui/dialog.tsx around lines 32 to 49, the
DialogContent component no longer includes a default close button, causing
dialogs to lack a dismissal control unless consumers add <DialogClose> manually.
To fix this, re-introduce a built-in close button inside the
DialogPrimitive.Content element by adding a <DialogClose> component wrapping a
button with an accessible label and close icon, positioned at the top-right
corner. This ensures all dialogs have a consistent, accessible close control
without requiring every usage to add it manually.
Description of change
evoting setup
Issue Number
n/a
Type of change
How the change has been tested
n/a
Change checklist
Summary by CodeRabbit
New Features
Bug Fixes
Style
Chores