Lewis/user portal - #65
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThe changes remove Nango integration code from existing actions and components while introducing a new portal setup. New configuration and documentation files for a Next.js application have been added, including environment settings, Tailwind, and TypeScript configurations. A set of new pages, components, and API routes establish an OTP-based authentication flow with internationalization support and error handling. Additionally, the database schema has been updated with new models and relationships for a user portal, and an OTP email template component has been added. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant B as Browser
participant P as Portal App
participant A as Auth API
participant E as Email Service
participant DB as Database
U->>B: Navigate to login page
B->>P: Request login page
P-->>B: Render OTP sign-in form
U->>B: Enter email and request OTP
B->>P: Submit login request with email
P->>A: Trigger OTP generation
A->>DB: Create/validate OTP record
A->>E: Send OTP email (OTPVerificationEmail)
E-->>U: Deliver OTP email
U->>B: Submit OTP for verification
B->>P: OTP verification request
P->>A: Validate OTP and sign in
A->>DB: Verify OTP & create session
DB-->>A: Return session info
A-->>P: Return session result
P-->>B: Render authenticated state
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (1)
🔇 Additional comments (1)
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 18
🧹 Nitpick comments (16)
apps/portal/src/app/lib/resend.ts (1)
1-4: ValidateRESEND_API_KEYon initialization.
To avoid runtime failures, consider validating thatenv.RESEND_API_KEYis defined and non-empty. This provides clearer error handling if the environment variable is missing or misconfigured.-export const resend = new Resend(env.RESEND_API_KEY); +if (!env.RESEND_API_KEY) { + throw new Error("RESEND_API_KEY is not defined in environment variables."); +} + +export const resend = new Resend(env.RESEND_API_KEY);apps/portal/src/app/[locale]/(public)/layout.tsx (1)
1-7: Remove theasynckeyword if not needed.
Currently, there is noawaitusage or asynchronous logic. If future code changes require async data fetching, you can re-introduce it. Otherwise, removing it now may reduce confusion.-export default async function Layout({ +export default function Layout({ children, }: { children: React.ReactNode; }) { return <>{children}</>; }apps/portal/src/app/locales/en.ts (1)
1-19: Consider adding translations for common error states.The translations are well-organized, but consider adding messages for common error scenarios:
- Invalid email format
- Rate limiting messages
- Network error states
- Generic error state
Example additions:
export default { auth: { title: "Employee Portal", description: "Enter your email and one time password to continue", options: "More options", email: { otp_sent: "One time password sent", otp_description: "Check your email for the one time password", otp_try_again: "Try again", placeholder: "Your work email", button: "Get one time password", + errors: { + invalid_email: "Please enter a valid email address", + rate_limit: "Too many attempts. Please try again later", + network_error: "Network error. Please check your connection", + generic: "Something went wrong. Please try again" + } }, }, // ... } as const;apps/portal/src/env.mjs (1)
6-8: Enhance validation for sensitive environment variables.Consider adding stricter validation for sensitive variables:
server: { - BETTER_AUTH_SECRET: z.string(), + BETTER_AUTH_SECRET: z.string().min(32), - BETTER_AUTH_URL: z.string(), + BETTER_AUTH_URL: z.string().url(), - RESEND_API_KEY: z.string(), + RESEND_API_KEY: z.string().regex(/^re_/), },apps/portal/src/app/components/otp-input.tsx (1)
26-26: Consider a more maintainable styling approach.The use of
!in the className to force styles might lead to specificity issues. Consider using Tailwind's built-in modifiers or a more maintainable styling approach.- className={cn("!w-12 !appearance-none selection:bg-none ", className)} + className={cn("[&]:w-12 [&]:appearance-none selection:bg-none", className)}apps/portal/src/app/[locale]/(app)/page.tsx (1)
37-55: Optimize database query with selective fields.Consider optimizing the database query by selecting only the required fields from the employee table.
export const getUser = unstable_cache(async (email: string) => { "use server"; const employee_data = await db.employee.findFirst({ where: { email, }, + select: { + id: true, + email: true, + organization: { + select: { + id: true, + name: true, + }, + }, + }, - include: { - organization: { - select: { - id: true, - name: true, - }, - }, - }, }); return employee_data; });apps/portal/src/app/[locale]/(public)/auth/page.tsx (1)
6-8: Enhance SEO with additional metadata.Consider adding more metadata fields for better SEO:
export const metadata: Metadata = { title: "Login | Comp AI", + description: "Secure login page for Comp AI using one-time password authentication", + robots: "noindex, nofollow", };packages/email/emails/otp.tsx (2)
62-64: Remove duplicate text in email body.The text "Your one-time password for Comp AI" appears twice in the email.
- <Text className="text-[14px] leading-[24px] text-[#121212]"> - Your one-time password for Comp AI - </Text>
27-47: Consider self-hosting fonts for reliability.Loading fonts from CDN could cause rendering issues if the CDN is down. Consider self-hosting the fonts or providing multiple fallback options.
apps/portal/src/app/components/otp-form.tsx (2)
36-37: Simplify loading state management.The component manages loading state twice with both
isLoadingandisExecuting. Consider using onlyisExecutingfromuseAction.- const [isLoading, setIsLoading] = useState(false); const router = useRouter(); const { execute, isExecuting } = useAction(login, { onSuccess: () => { toast.success("OTP verified"); router.push("/"); }, onError: (error) => { toast.error(error.error.serverError as string); }, });Update the button to use
isExecuting:- disabled={isLoading} + disabled={isExecuting}Also applies to: 46-54
56-69: Simplify error handling in onSubmit.The try-catch block with loading state management can be removed since error handling is already managed by
useAction.const onSubmit = async (formData: OtpFormValues) => { - try { - setIsLoading(true); - - await execute({ - otp: formData.otp, - email: formData.email, - }); - } catch (error) { - toast.error("An unexpected error occurred"); - } finally { - setIsLoading(false); - } + await execute({ + otp: formData.otp, + email: formData.email, + }); };apps/portal/src/app/components/otp.tsx (2)
29-29: Rename state variable for clarity.The
_emailvariable name with underscore prefix is unconventional. Consider a more descriptive name.- const [_email, setEmail] = useState<string>(); + const [verificationEmail, setVerificationEmail] = useState<string>();
42-54: Improve error handling and state updates.The success case doesn't explicitly check for
data, and state updates could be more consistent.const { data, error } = await authClient.emailOtp.sendVerificationOtp({ email: email, type: "sign-in", }); + setLoading(false); + if (error) { - setLoading(false); toast.error(error.message); + return; } + if (!data) { + toast.error("Failed to send verification code"); + return; + } + setSent(true); - setLoading(false);apps/portal/tsconfig.json (1)
3-3: Consider updating the TypeScript target.The
targetis set toES2017which might be too conservative. Consider updating to a more recent target likeES2020orES2021to enable modern JavaScript features while maintaining broad browser compatibility.packages/db/prisma/schema.prisma (2)
978-994: Implementation of PortalUser ModelThe new
PortalUsermodel defines essential fields for managing portal users along with relationships to sessions, accounts, and employees. Consider whether adding default values (such as@default(now())) forcreatedAtandupdatedAtmight improve consistency with other models in your schema.
1010-1028: Review of PortalAccount ModelThe
PortalAccountmodel effectively captures external account token information, along with expiration and credential details. You might want to review whether adding an index or even a uniqueness constraint on fields likeaccountIdcould be beneficial for query performance, depending on how these are used in your application.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (10)
apps/portal/public/apple-touch-icon.pngis excluded by!**/*.pngapps/portal/public/favicon-96x96.pngis excluded by!**/*.pngapps/portal/public/favicon.icois excluded by!**/*.icoapps/portal/public/favicon.svgis excluded by!**/*.svgapps/portal/public/fonts/GeneralSans-Variable.ttfis excluded by!**/*.ttfapps/portal/public/fonts/GeneralSans-VariableItalic.ttfis excluded by!**/*.ttfapps/portal/public/web-app-manifest-192x192.pngis excluded by!**/*.pngapps/portal/public/web-app-manifest-512x512.pngis excluded by!**/*.pngbun.lockis excluded by!**/*.lockyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (38)
apps/app/src/actions/integrations/delete-integration-connection.ts(0 hunks)apps/app/src/actions/integrations/retrieve-integration-session-token.ts(1 hunks)apps/app/src/components/integrations/integrations-card.tsx(0 hunks)apps/portal/.gitignore(1 hunks)apps/portal/README.md(1 hunks)apps/portal/next.config.ts(1 hunks)apps/portal/package.json(1 hunks)apps/portal/postcss.config.mjs(1 hunks)apps/portal/public/site.webmanifest(1 hunks)apps/portal/src/app/[locale]/(app)/page.tsx(1 hunks)apps/portal/src/app/[locale]/(public)/auth/page.tsx(1 hunks)apps/portal/src/app/[locale]/(public)/layout.tsx(1 hunks)apps/portal/src/app/[locale]/layout.tsx(1 hunks)apps/portal/src/app/[locale]/not-found.tsx(1 hunks)apps/portal/src/app/[locale]/providers.tsx(1 hunks)apps/portal/src/app/actions/login.ts(1 hunks)apps/portal/src/app/api/auth/[...all]/route.ts(1 hunks)apps/portal/src/app/components/otp-form.tsx(1 hunks)apps/portal/src/app/components/otp-input.tsx(1 hunks)apps/portal/src/app/components/otp.tsx(1 hunks)apps/portal/src/app/global-error.tsx(1 hunks)apps/portal/src/app/lib/auth-client.ts(1 hunks)apps/portal/src/app/lib/auth.ts(1 hunks)apps/portal/src/app/lib/resend.ts(1 hunks)apps/portal/src/app/locales/client.ts(1 hunks)apps/portal/src/app/locales/en.ts(1 hunks)apps/portal/src/app/locales/es.ts(1 hunks)apps/portal/src/app/locales/fr.ts(1 hunks)apps/portal/src/app/locales/no.ts(1 hunks)apps/portal/src/app/locales/pt.ts(1 hunks)apps/portal/src/app/locales/server.ts(1 hunks)apps/portal/src/env.mjs(1 hunks)apps/portal/src/middleware.ts(1 hunks)apps/portal/tailwind.config.ts(1 hunks)apps/portal/tsconfig.json(1 hunks)packages/db/prisma/migrations/20250218153849_employee_portal/migration.sql(1 hunks)packages/db/prisma/schema.prisma(2 hunks)packages/email/emails/otp.tsx(1 hunks)
💤 Files with no reviewable changes (2)
- apps/app/src/components/integrations/integrations-card.tsx
- apps/app/src/actions/integrations/delete-integration-connection.ts
✅ Files skipped from review due to trivial changes (7)
- apps/portal/src/app/locales/no.ts
- apps/portal/src/app/locales/es.ts
- apps/portal/src/app/locales/pt.ts
- apps/portal/src/app/locales/fr.ts
- apps/portal/README.md
- apps/portal/public/site.webmanifest
- apps/portal/.gitignore
🔇 Additional comments (19)
apps/app/src/actions/integrations/retrieve-integration-session-token.ts (1)
18-19:Details
❓ Verification inconclusive
Verify the unused
integrationIdparameter.The action accepts
integrationIdbut doesn't use it in the token generation. This suggests the integration flow might be incomplete.Let's verify the integration flow implementation:
🏁 Script executed:
#!/bin/bash # Description: Check how integrationId is used across the codebase # Search for references to integrationId rg "integrationId" -A 5 # Search for other integration-related files fd "integration" --type fLength of output: 7512
Action Required: Confirm Usage of
integrationIdin Token GenerationThe
retrieve-integration-session-token.tsaction currently destructures theintegrationIdfrom its input but does not utilize it when generating the session token (which is currently hardcoded as"123"). In contrast, other integration-related actions (e.g., in delete integration connection and integration settings) actively use this parameter. Please verify whether:
- This omission is intentional—for example, if the token generation is a stub or placeholder implementation.
- The integration flow is incomplete and whether the token generation should incorporate the
integrationId.If the parameter is not required, consider removing it or adding an explanatory comment. Otherwise, update the token generation flow accordingly.
apps/portal/src/app/lib/auth.ts (2)
1-9: Imports are clear and concise.
All imports from@bubba/db,@bubba/email, andbetter-authare straightforward, and file scoping appears correct.
10-25: Configuration mappings look correct.
The specified models (PortalUser,PortalSession,PortalAccount,PortalVerification) properly align with the authentication structure. Verify that these model names match the actual Prisma schema definitions to avoid runtime issues.apps/portal/src/app/api/auth/[...all]/route.ts (1)
1-4: LGTM! Clean and efficient implementation.The implementation follows Next.js best practices by using a catch-all route handler and leveraging the
better-authpackage'stoNextJsHandlerutility to handle authentication requests.apps/portal/postcss.config.mjs (1)
1-8: LGTM! Clean PostCSS configuration.The configuration is properly typed and includes the necessary Tailwind CSS plugin.
apps/portal/src/app/lib/auth-client.ts (1)
5-10:Details
❓ Verification inconclusive
Review security implications of client-side configuration.
Please consider the following security aspects:
- The base URL is exposed to the client side through
NEXT_PUBLIC_prefix. Verify if this exposure is necessary and intended.- Consider adding CSRF protection and other security configurations supported by the
better-authpackage.
🌐 Web query:
What security configurations does better-auth support for client-side authentication?💡 Result:
Better Auth provides several robust security configurations for client-side authentication, focusing on protecting user sessions, preventing attacks, and ensuring secure integration with various authentication methods. Here are the key security features and their configurations:
Session Management
- Secure Cookies: Automatically enabled when using HTTPS, cookies are encrypted with
SameSite=LaxandHttpOnlyattributes to prevent cross-site request forgery (CSRF) and client-side script access[1][7].- Session Expiration: Default session duration is 7 days, with auto-renewal if used within the
updateAgethreshold (default: 1 day)[1].- Revocation: Sessions can be manually revoked server-side or by users to log out from specific devices[1].
CSRF and Open Redirect Protection
- Origin Validation: Requests are blocked if the
OriginorRefererheaders don’t match thetrustedOriginslist[7][10].- State Parameters: OAuth flows use stored state values to prevent CSRF during redirects[1][7].
Authentication Methods
- OAuth with PKCE: Secures social logins (Google, GitHub, etc.) by generating a code verifier/challenge pair to prevent code interception[1][4].
- Password Hashing: Uses
scrypt(memory-hard and CPU-intensive) by default, with customizable hashing/verification functions[1].Rate Limiting
- Built-in protection against brute-force attacks across all routes, with stricter limits on high-risk endpoints[1][4].
Advanced Configurations
- Trusted Origins: Define allowed domains to block unauthorized redirects[1][7].
- Cross-Subdomain Cookies: Enable via
crossSubDomainoption for shared authentication across subdomains[1].- Custom Cookies: Rename cookies to reduce fingerprinting risks[1].
Extensions via Plugins
- Multi-Factor Authentication (MFA): Add layers like TOTP or biometrics using plugins[2][5].
- Certificate-Based Authentication: While not native, plugins could integrate mutual TLS (mTLS) for client certificates[9].
For client-side implementation, developers must invoke methods like
signIn.emailorsignIn.socialfrom the frontend while relying on server-side session validation[2][4]. Secure cookies ensure credentials remain protected during transit and storage[1][7].Citations:
- 1: https://www.better-auth.com/docs/reference/security
- 2: https://www.better-auth.com/docs/basic-usage
- 3: https://docs.solace.com/Security/Configuring-Client-Authentication.htm
- 4: https://www.better-auth.com/docs/reference/options
- 5: https://www.idrnd.ai/5-authentication-methods-that-can-prevent-the-next-breach/
- 6: https://www.securew2.com/blog/tls-authentication-works
- 7: https://github.com/better-auth/better-auth/blob/main/SECURITY.md
- 8: https://techcommunity.microsoft.com/t5/microsoft-entra-blog/authentication-strength-choose-the-right-auth-method-for-your/ba-p/2365674
- 9: https://www.jscape.com/blog/client-certificate-authentication
- 10: https://github.com/better-auth/better-auth/security
Action: Validate Client-Side Auth Security Settings
- The file
apps/portal/src/app/lib/auth-client.tscurrently exposes the base URL via theNEXT_PUBLIC_BETTER_AUTH_URLenvironment variable. Confirm that this exposure is intentional and appropriate for your authentication flow.- While Better Auth offers built-in security features—such as secure cookies with
SameSite,HttpOnlyattributes, and CSRF protection via origin validation—please verify that these configurations are enabled and correctly applied on the server side.- If these protections are not already activated in your overall setup, consider integrating explicit configurations for secure cookies and CSRF defense as part of your authentication strategy.
apps/portal/tailwind.config.ts (1)
1-11: LGTM!The Tailwind configuration is well-structured with:
- Proper extension of the base configuration
- Correct content paths for local and shared packages
- Type-safe configuration using the
satisfiesoperatorapps/portal/src/app/[locale]/not-found.tsx (1)
1-16: LGTM! Well-structured 404 page implementation.The component follows Next.js best practices with proper async handling for i18n, clear error messaging, and a user-friendly return link. The layout is clean and responsive.
apps/portal/next.config.ts (1)
12-27: LGTM! Well-configured PostHog rewrites.The rewrite rules are correctly configured for PostHog integration, providing proper endpoint mappings.
apps/portal/src/env.mjs (1)
11-15: LGTM! Well-structured client environment variables.The client environment variables are correctly separated and typed, with appropriate optional flags for PostHog configuration.
apps/portal/src/app/[locale]/providers.tsx (1)
30-46: LGTM! Well-structured provider configuration.The provider configuration is well-organized, with proper theme settings and conditional analytics rendering.
apps/portal/src/middleware.ts (2)
6-10: LGTM! Comprehensive i18n configuration.The internationalization setup supports multiple locales and follows best practices.
25-37: LGTM! Secure path handling and redirects.The path handling implementation correctly manages locales and implements secure redirects.
apps/portal/src/app/[locale]/(public)/auth/page.tsx (1)
21-43: LGTM! Well-structured responsive layout.The layout implementation is clean and responsive, with proper spacing and alignment for different screen sizes.
apps/portal/src/app/components/otp.tsx (1)
74-82: LGTM! Well-configured input field.The input field is properly configured with appropriate attributes for better user experience.
packages/db/prisma/migrations/20250218153849_employee_portal/migration.sql (1)
7-9: 🛠️ Refactor suggestionAdd NOT NULL constraints for essential fields.
The
nameandemailVerifiedfields inportal_usershould be nullable as they might not be available immediately upon user creation.Update the field constraints:
- "name" TEXT NOT NULL, + "name" TEXT, "email" TEXT NOT NULL, - "emailVerified" BOOLEAN NOT NULL, + "emailVerified" BOOLEAN NOT NULL DEFAULT false,Likely an incorrect or invalid review comment.
packages/db/prisma/schema.prisma (3)
830-832: New Employee Portal Linking Fields in Employee ModelThe addition of
linkIdand the associated relationlinkin theEmployeemodel correctly establishes an optional link to aPortalUser. Please verify that usingonDelete: SetNullmeets your business requirements for handling deletions of portal users.
996-1009: PortalSession Model for User SessionsThe
PortalSessionmodel is well-structured for tracking session details and associating sessions with portal users. As with thePortalUsermodel, consider defaulting the timestamp fields (createdAtandupdatedAt) if it aligns with your design preferences.
1030-1039: PortalVerification Model for OTP ProcessThe
PortalVerificationmodel provides a simple yet sufficient structure for managing verification tokens. Confirm that handling of datetime values (especially forexpiresAt) in the application logic accommodates timezone differences and validity checks consistently.
| return { | ||
| success: true, | ||
| sessionToken: response.data.token, | ||
| sessionToken: "123", |
There was a problem hiding this comment.
Critical: Replace hardcoded session token with secure token generation.
The hardcoded token "123" is a significant security vulnerability that could lead to unauthorized access. This appears to be a temporary placeholder after removing the Nango integration.
Please implement proper session token generation with:
- Cryptographically secure random values
- Limited token lifetime
- Proper authentication and authorization checks
- Token validation against the specific integration and user
| plugins: [ | ||
| nextCookies(), | ||
| emailOTP({ | ||
| otpLength: 6, | ||
| expiresIn: 10 * 60, | ||
| async sendVerificationOTP({ email, otp }) { | ||
| await sendEmail({ | ||
| to: email, | ||
| subject: "One-Time Password for Comp AI", | ||
| react: OTPVerificationEmail({ email, otp }), | ||
| }); | ||
| } | ||
| }) | ||
| ] | ||
| }); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add error handling around email sending.
The sendVerificationOTP function awaits sendEmail but does not handle potential errors. Consider wrapping this call in a try/catch block to log or handle failures gracefully.
async sendVerificationOTP({ email, otp }) {
- await sendEmail({
- to: email,
- subject: "One-Time Password for Comp AI",
- react: OTPVerificationEmail({ email, otp }),
- });
+ try {
+ await sendEmail({
+ to: email,
+ subject: "One-Time Password for Comp AI",
+ react: OTPVerificationEmail({ email, otp }),
+ });
+ } catch (error) {
+ // Log or handle the error accordingly
+ console.error("Failed to send verification email:", error);
+ }
}📝 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.
| plugins: [ | |
| nextCookies(), | |
| emailOTP({ | |
| otpLength: 6, | |
| expiresIn: 10 * 60, | |
| async sendVerificationOTP({ email, otp }) { | |
| await sendEmail({ | |
| to: email, | |
| subject: "One-Time Password for Comp AI", | |
| react: OTPVerificationEmail({ email, otp }), | |
| }); | |
| } | |
| }) | |
| ] | |
| }); | |
| plugins: [ | |
| nextCookies(), | |
| emailOTP({ | |
| otpLength: 6, | |
| expiresIn: 10 * 60, | |
| async sendVerificationOTP({ email, otp }) { | |
| try { | |
| await sendEmail({ | |
| to: email, | |
| subject: "One-Time Password for Comp AI", | |
| react: OTPVerificationEmail({ email, otp }), | |
| }); | |
| } catch (error) { | |
| // Log or handle the error accordingly | |
| console.error("Failed to send verification email:", error); | |
| } | |
| } | |
| }) | |
| ] | |
| }); |
| export default function GlobalError() { | ||
| return ( | ||
| <html lang="en"> | ||
| <body> | ||
| <NextError statusCode={0} /> | ||
| </body> | ||
| </html> | ||
| ); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Enhance error handling implementation.
The current implementation has several areas for improvement:
- Status code 0 is not a standard HTTP status code
- The component doesn't utilize error details for debugging
- Missing error props that Next.js provides to error components
Consider this implementation:
-export default function GlobalError() {
+export default function GlobalError({
+ error,
+ reset,
+}: {
+ error: Error & { digest?: string }
+ reset: () => void
+}) {
+ console.error(error)
return (
<html lang="en">
<body>
- <NextError statusCode={0} />
+ <NextError statusCode={500} />
+ <button onClick={reset}>Try again</button>
</body>
</html>
);
}📝 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 default function GlobalError() { | |
| return ( | |
| <html lang="en"> | |
| <body> | |
| <NextError statusCode={0} /> | |
| </body> | |
| </html> | |
| ); | |
| } | |
| export default function GlobalError({ | |
| error, | |
| reset, | |
| }: { | |
| error: Error & { digest?: string } | |
| reset: () => void | |
| }) { | |
| console.error(error) | |
| return ( | |
| <html lang="en"> | |
| <body> | |
| <NextError statusCode={500} /> | |
| <button onClick={reset}>Try again</button> | |
| </body> | |
| </html> | |
| ); | |
| } |
| en: () => import("./en"), | ||
| es: () => import("./es"), | ||
| fr: () => import("./fr"), | ||
| no: () => import("./no"), |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Update Norwegian language code to follow ISO standards.
The language code 'no' for Norwegian is deprecated. Use 'nb' for Bokmål or 'nn' for Nynorsk according to ISO 639-1 standards.
| .action(async ({ parsedInput }) => { | ||
| await auth.api.signInEmailOTP({ | ||
| body: { | ||
| email: parsedInput.email, | ||
| otp: parsedInput.otp, | ||
| }, | ||
| }); | ||
|
|
||
| return { | ||
| success: true, | ||
| }; | ||
| }); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Enhance error handling in the login action.
The current implementation doesn't handle potential errors from the signInEmailOTP call. Consider adding proper error handling to provide meaningful feedback to users.
Apply this diff to improve error handling:
.action(async ({ parsedInput }) => {
- await auth.api.signInEmailOTP({
- body: {
- email: parsedInput.email,
- otp: parsedInput.otp,
- },
- });
-
- return {
- success: true,
- };
+ try {
+ await auth.api.signInEmailOTP({
+ body: {
+ email: parsedInput.email,
+ otp: parsedInput.otp,
+ },
+ });
+ return { success: true };
+ } catch (error) {
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Authentication failed',
+ };
+ }
});📝 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.
| .action(async ({ parsedInput }) => { | |
| await auth.api.signInEmailOTP({ | |
| body: { | |
| email: parsedInput.email, | |
| otp: parsedInput.otp, | |
| }, | |
| }); | |
| return { | |
| success: true, | |
| }; | |
| }); | |
| .action(async ({ parsedInput }) => { | |
| try { | |
| await auth.api.signInEmailOTP({ | |
| body: { | |
| email: parsedInput.email, | |
| otp: parsedInput.otp, | |
| }, | |
| }); | |
| return { success: true }; | |
| } catch (error) { | |
| return { | |
| success: false, | |
| error: error instanceof Error ? error.message : 'Authentication failed', | |
| }; | |
| } | |
| }); |
| "next": "15.1.7", | ||
| "react": "^19.0.0", | ||
| "react-dom": "^19.0.0", | ||
| "react-otp-input": "^3.1.1" |
There was a problem hiding this comment.
Verify package versions.
Several package versions appear to be incorrect or not yet released:
next: "15.1.7"- Latest stable version is 14.xreact: "^19.0.0"- React 19 is not yet releasedreact-dom: "^19.0.0"- Should match React version
Update the versions to currently available releases:
- "next": "15.1.7",
- "react": "^19.0.0",
- "react-dom": "^19.0.0",
+ "next": "^14.1.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",📝 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.
| "next": "15.1.7", | |
| "react": "^19.0.0", | |
| "react-dom": "^19.0.0", | |
| "react-otp-input": "^3.1.1" | |
| "next": "^14.1.0", | |
| "react": "^18.2.0", | |
| "react-dom": "^18.2.0", | |
| "react-otp-input": "^3.1.1" |
| export const viewport = { | ||
| width: "device-width", | ||
| initialScale: 1, | ||
| maximumScale: 1, | ||
| userScalable: false, | ||
| themeColor: [ | ||
| { media: "(prefers-color-scheme: light)" }, | ||
| { media: "(prefers-color-scheme: dark)" }, | ||
| ], | ||
| }; |
There was a problem hiding this comment.
Improve accessibility by allowing user scaling.
The current viewport settings prevent users from zooming, which is an accessibility concern. Users should be able to zoom for better readability.
Update the viewport settings:
export const viewport = {
width: "device-width",
initialScale: 1,
- maximumScale: 1,
- userScalable: false,
+ maximumScale: 5,
+ userScalable: true,
themeColor: [
{ media: "(prefers-color-scheme: light)" },
{ media: "(prefers-color-scheme: dark)" },
],
};📝 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 viewport = { | |
| width: "device-width", | |
| initialScale: 1, | |
| maximumScale: 1, | |
| userScalable: false, | |
| themeColor: [ | |
| { media: "(prefers-color-scheme: light)" }, | |
| { media: "(prefers-color-scheme: dark)" }, | |
| ], | |
| }; | |
| export const viewport = { | |
| width: "device-width", | |
| initialScale: 1, | |
| maximumScale: 5, | |
| userScalable: true, | |
| themeColor: [ | |
| { media: "(prefers-color-scheme: light)" }, | |
| { media: "(prefers-color-scheme: dark)" }, | |
| ], | |
| }; |
| const font = localFont({ | ||
| src: "/../../../public/fonts/GeneralSans-Variable.ttf", | ||
| display: "swap", | ||
| variable: "--font-general-sans", | ||
| }); |
There was a problem hiding this comment.
Fix font path resolution.
The font path seems incorrect. In Next.js, public files should be referenced from the root.
Update the font path:
const font = localFont({
- src: "/../../../public/fonts/GeneralSans-Variable.ttf",
+ src: "../../../public/fonts/GeneralSans-Variable.ttf",
display: "swap",
variable: "--font-general-sans",
});Committable suggestion skipped: line range outside the PR's diff.
| -- AddForeignKey | ||
| ALTER TABLE "Employee" ADD CONSTRAINT "Employee_linkId_fkey" FOREIGN KEY ("linkId") REFERENCES "portal_user"("id") ON DELETE SET NULL ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "portal_session" ADD CONSTRAINT "portal_session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "portal_user"("id") ON DELETE CASCADE ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "portal_account" ADD CONSTRAINT "portal_account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "portal_user"("id") ON DELETE CASCADE ON UPDATE CASCADE; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add indexes for foreign key columns.
Foreign key columns should be indexed for better query performance.
Add the following indexes:
-- Add indexes for foreign key columns
CREATE INDEX "Employee_linkId_idx" ON "Employee"("linkId");
CREATE INDEX "portal_session_userId_idx" ON "portal_session"("userId");
CREATE INDEX "portal_account_userId_idx" ON "portal_account"("userId");| "createdAt" TIMESTAMP(3), | ||
| "updatedAt" TIMESTAMP(3), |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add NOT NULL constraints for timestamp fields.
The createdAt and updatedAt fields in portal_verification should be NOT NULL to maintain consistency with other tables.
Update the field constraints:
"expiresAt" TIMESTAMP(3) NOT NULL,
- "createdAt" TIMESTAMP(3),
- "updatedAt" TIMESTAMP(3),
+ "createdAt" TIMESTAMP(3) NOT NULL,
+ "updatedAt" TIMESTAMP(3) NOT 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.
| "createdAt" TIMESTAMP(3), | |
| "updatedAt" TIMESTAMP(3), | |
| "expiresAt" TIMESTAMP(3) NOT NULL, | |
| - "createdAt" TIMESTAMP(3), | |
| - "updatedAt" TIMESTAMP(3), | |
| + "createdAt" TIMESTAMP(3) NOT NULL, | |
| + "updatedAt" TIMESTAMP(3) NOT NULL, |
Summary by CodeRabbit
New Features
Integrations