Conversation
…to backend_brandSettings
|
The preview deployment is in progress. 🟡 Last updated at: 2025-02-13 12:19:32 CET |
WalkthroughThis pull request implements a comprehensive update across the project. New IDE and project configurations are introduced, and dependency as well as package management settings are revised. Several new API endpoints and middleware functions handle brand settings, files, prompts, questions, bot credentials, and authentication. Moreover, a wide array of React components for admin interfaces, dashboards, chat UIs, and knowledge bases are added along with a full suite of new UI components. New Zustand stores and custom hooks provide state management, while numerous Mongoose schemas and models support data persistence. Import paths have been reorganized to reflect the new directory structure. Changes
Sequence Diagram(s)sequenceDiagram
participant C as Client
participant API as BrandSettings API
participant FS as File System
participant DB as Database
C->>API: POST /brandsettings (formData with logo and settings)
API->>FS: Validate and save logo file
API->>DB: Check for existing brand settings
alt Exists
DB-->>API: Existing settings found
API->>DB: Update settings with new data
else Not Exists
API->>DB: Create new brand settings entry
end
API-->>C: Return success response
sequenceDiagram
participant C as Client
participant API as Registration API
participant DB as Database
participant JWT as JWT Service
C->>API: POST /auth/register (user details)
API->>DB: Query user by email
alt User exists
DB-->>API: User found
API-->>C: Return error (user exists)
else New user
API->>DB: Hash password & create user record
DB-->>API: New user data
API->>JWT: Generate JWT token with user ID
JWT-->>API: Return token
API-->>C: Return user data (without password) and token
end
Poem
✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 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.
Caution
Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.
🛑 Comments failed to post (81)
src/app/(chat)/layout.tsx (1)
21-26:
⚠️ Potential issueConsider accessibility implications of fixed viewport scale.
Setting
maximumScale: 1prevents users from zooming the page, which can create accessibility issues for users with visual impairments.Apply this diff to improve accessibility:
export const viewport: Viewport = { themeColor: 'black', initialScale: 1, - maximumScale: 1, + maximumScale: 5, width: 'device-width', }📝 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: Viewport = { themeColor: 'black', initialScale: 1, maximumScale: 5, width: 'device-width', }src/app/(chat)/_components/GeneralSidebar.tsx (1)
79-79:
⚠️ Potential issueFix incomplete class name.
The class name
-300appears to be incomplete or incorrect. This could be a Tailwind class that was partially deleted (e.g.,bg-gray-300).Please verify and fix the class name. If it's meant to be a background color class, you might want to apply this diff:
- <div className='-300 h-screen bg-[#EBEBEB] text-white'> + <div className='h-screen bg-[#EBEBEB] text-white'>📝 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='h-screen bg-[#EBEBEB] text-white'>src/lib/auth.ts (1)
1-3: 💡 Verification agent
🧩 Analysis chain
Verify the use of bcryptjs and NextAuth versions.
Make sure the pinned versions are secure and stable, as outdated credentials or hashing libraries can introduce vulnerabilities.
🏁 Script executed:
#!/bin/bash # Checking installed versions of bcryptjs and next-auth grep '"bcryptjs":' package.json grep '"next-auth":' package.jsonLength of output: 128
Action Required: Revisit NextAuth Beta Usage
After verifying the package versions, we have:
- bcryptjs:
"^2.4.3"– This appears to be current.- next-auth:
"5.0.0-beta.25"– This beta release may not offer the same stability and security guarantees as a stable release.Please confirm that using a beta version of NextAuth is intentional. If production security and stability are priorities, consider switching to a stable version.
src/app/api/(admin)/knowledgebase/file/route.ts (1)
115-127: 🛠️ Refactor suggestion
Implement pagination for large knowledge base retrievals.
If there are numerous uploaded files, returning all documents at once could degrade performance. Consider a paginated response.src/components/ui/chart.tsx (1)
85-86:
⚠️ Potential issueAvoid using
dangerouslySetInnerHTMLwithout sanitizing user-controlled data.
Ifconfigcan include untrusted input, it might introduce an XSS risk. Consider generating CSS strings via a safer method or ensureconfigis always controlled and sanitized.-<style - dangerouslySetInnerHTML={{ __html: Object.entries(THEMES)... -}} +/******************************* + * Potential safer approach + *******************************/ +{Object.entries(THEMES).map(([theme, prefix]) => ( + <style key={theme} data-theme={theme}> + { /* Generate required rules here in a safe manner */ } + </style> +))}📝 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./******************************* * Potential safer approach *******************************/ {Object.entries(THEMES).map(([theme, prefix]) => ( <style key={theme} data-theme={theme}> { /* Generate required rules here in a safe manner */ } </style> ))}🧰 Tools
🪛 Biome (1.9.4)
[error] 86-86: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
src/app/(admin)/_components/AuthSession.tsx (1)
12-20: 🛠️ Refactor suggestion
⚠️ Potential issueConsider security implications and add cleanup handling.
- Storing sensitive data like user ID in localStorage poses security risks. Consider using more secure alternatives like HTTP-only cookies.
- Add cleanup logic to remove stored data when the component unmounts.
export const AuthSession = ({ session }: { session: TSession }) => { useEffect(() => { if (session?.user) { - localStorage.setItem('user', JSON.stringify(session.user.id)) + // TODO: Use a more secure storage mechanism + // For now, at least add cleanup on unmount } + return () => { + localStorage.removeItem('user') + } }, [session]) return 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.export const AuthSession = ({ session }: { session: TSession }) => { useEffect(() => { if (session?.user) { // TODO: Use a more secure storage mechanism // For now, at least add cleanup on unmount } return () => { localStorage.removeItem('user') } }, [session]) return null }src/models/botCredentials/Bot.model.ts (1)
3-18:
⚠️ Potential issueConsider encrypting sensitive data.
The schema stores the OpenAI API key as plain text. Consider encrypting sensitive credentials before storing them in the database.
Here's a recommended approach:
- Add encryption/decryption middleware to the schema
- Use environment variables for the encryption key
- Encrypt the API key before saving and decrypt when retrieving
Would you like me to provide an example implementation of the encryption middleware?
src/models/knowledgeBase/File.model.ts (1)
5-8:
⚠️ Potential issueFix typo in the required field.
There's a typo in the
requiredfield which will prevent proper validation.fileName: { type: String, - reqired: true, + required: true, },📝 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.fileName: { type: String, required: true, },src/models/user/user.model.ts (2)
17-20:
⚠️ Potential issueAdd password hashing middleware for security.
The password field should be hashed before storage to ensure security.
Add this pre-save middleware to hash the password:
import bcrypt from 'bcrypt'; UserSchema.pre('save', async function(next) { if (!this.isModified('password')) return next(); try { const salt = await bcrypt.genSalt(10); this.password = await bcrypt.hash(this.password, salt); next(); } catch (error) { next(error as Error); } });
3-23: 🛠️ Refactor suggestion
Add email validation and uniqueness constraint.
The schema structure looks good, but the email field should be unique and validated to ensure data integrity.
email: { type: String, required: true, + unique: true, + validate: { + validator: function(v: string) { + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v); + }, + message: (props: { value: string }) => `${props.value} is not a valid email!` + } },📝 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 UserSchema = new mongoose.Schema( { firstName: { type: String, required: true, }, lastName: { type: String, required: true, }, email: { type: String, required: true, unique: true, validate: { validator: function(v: string) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v); }, message: (props: { value: string }) => `${props.value} is not a valid email!` } }, password: { type: String, required: true, }, }, { timestamps: true }, )src/app/api/(admin)/knowledgebase/file/[id]/route.ts (1)
4-23: 🛠️ Refactor suggestion
Enhance error handling and response data.
The route needs better error handling and more informative responses.
export const DELETE = async ( request: NextRequest, { params }: { params: { id: string } } ) => { try { const { id } = params; - const file = await FileModel.findByIdAndDelete(id) + const file = await FileModel.findById(id); + + if (!file) { + return NextResponse.json( + { error: "File not found" }, + { status: 404 } + ); + } + + await file.deleteOne(); return NextResponse.json( - { message: "File Deleted" }, + { + message: "File deleted successfully", + deletedFile: { + id: file._id, + name: file.name + } + }, { status: 200 } ); } catch (error) { + console.error('Error deleting file:', error); return NextResponse.json( - { error: "Internal Server Error" }, + { + error: "Internal Server Error", + message: error instanceof Error ? error.message : "Unknown error occurred" + }, { status: 500 } ); } };📝 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 DELETE = async ( request: NextRequest, { params }: { params: { id: string } } ) => { try { const { id } = params; const file = await FileModel.findById(id); if (!file) { return NextResponse.json( { error: "File not found" }, { status: 404 } ); } await file.deleteOne(); return NextResponse.json( { message: "File deleted successfully", deletedFile: { id: file._id, name: file.name } }, { status: 200 } ); } catch (error) { console.error('Error deleting file:', error); return NextResponse.json( { error: "Internal Server Error", message: error instanceof Error ? error.message : "Unknown error occurred" }, { status: 500 } ); } };src/hooks/use-mobile.tsx (1)
8-16: 🛠️ Refactor suggestion
Handle server-side rendering.
The hook uses browser-only APIs (
window.matchMediaandwindow.innerWidth) which are not available during server-side rendering. This could cause hydration errors.Apply this diff to handle server-side rendering:
export function useIsMobile() { const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined) React.useEffect(() => { + if (typeof window === 'undefined') return + const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) const onChange = () => { setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) } mql.addEventListener("change", onChange) setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) return () => mql.removeEventListener("change", onChange) }, []) return !!isMobile }📝 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 function useIsMobile() { const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined) React.useEffect(() => { if (typeof window === 'undefined') return const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) const onChange = () => { setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) } mql.addEventListener("change", onChange) setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) return () => mql.removeEventListener("change", onChange) }, []) return !!isMobile }src/components/ui/toaster.tsx (1)
3-3: 🛠️ Refactor suggestion
Fix import path and improve props spreading.
- The import path for
useToastis incorrect (should be@/hooks/use-toast).- Spreading unknown props directly to the DOM could lead to security issues.
Apply these diffs:
-import { useToast } from "@/components/hooks/use-toast" +import { useToast } from "@/hooks/use-toast"- <Toast key={id} {...props}> + <Toast key={id} {...(props as React.ComponentProps<typeof Toast>)}>Also applies to: 20-20
src/app/api/(admin)/bot/route.ts (2)
8-9:
⚠️ Potential issueAdd input validation for required fields.
The request body is parsed without validating the required fields. This could lead to runtime errors if any of the fields are missing.
Add validation before destructuring:
const reqBody = await request.json() + if (!reqBody.user || !reqBody.botName || !reqBody.openAIKey) { + return NextResponse.json( + { error: 'Missing required fields' }, + { status: 400 } + ) + } const { user, botName, openAIKey } = reqBody📝 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 reqBody = await request.json() if (!reqBody.user || !reqBody.botName || !reqBody.openAIKey) { return NextResponse.json( { error: 'Missing required fields' }, { status: 400 } ) } const { user, botName, openAIKey } = reqBody
36-39: 🛠️ Refactor suggestion
Improve error handling with specific error messages.
The current error handling returns a generic "Internal Server Error" message, which makes debugging difficult.
Add specific error handling:
} catch (error) { + console.error('Bot credentials operation failed:', error) return NextResponse.json( - { error: 'Internal Server Error' }, + { error: error instanceof Error ? error.message : 'Internal Server Error' }, { status: 500 }, )📝 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.} catch (error) { console.error('Bot credentials operation failed:', error) return NextResponse.json( { error: error instanceof Error ? error.message : 'Internal Server Error' }, { status: 500 }, ) }src/apis/admin/brandSettings.ts (1)
51-51:
⚠️ Potential issueFix incorrect error message.
The error message mentions "Error in adding the Prompt" but this function handles brand settings.
- throw new Error('Error in adding the Prompt') + throw new Error('Failed to add brand settings')📝 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.throw new Error('Failed to add brand settings')src/app/(admin)/layout.tsx (1)
20-31:
⚠️ Potential issueAdd missing dependency to useEffect.
The
setUserfunction is used within useEffect but not included in the dependency array.- }, []) + }, [setUser])📝 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 storedUser = localStorage.getItem('user') if (storedUser) { try { const parsedUser = JSON.parse(storedUser) setUser(parsedUser) } catch (error) { console.error('Failed to parse user data from localStorage', error) } } }, [setUser])src/app/(chat)/_utils/store/knowledge-store.ts (2)
33-37:
⚠️ Potential issueFix type mismatch in initial state.
The
questionsarray is included in the initial state but not defined in theStateinterface.interface State { prompt: string preset: number modelConfiguration: { temperature: number topP: number frequency: number pressure: number } + questions: singleQuestion[] setPrompt: (newPrompt: string) => void setPreset: (newPreset: number) => void setModelConfiguration: (newModel: Partial<State['modelConfiguration']>) => void }📝 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.interface State { prompt: string preset: number modelConfiguration: { temperature: number topP: number frequency: number pressure: number } questions: singleQuestion[] setPrompt: (newPrompt: string) => void setPreset: (newPreset: number) => void setModelConfiguration: (newModel: Partial<State['modelConfiguration']>) => void }
27-32: 💡 Verification agent
🧩 Analysis chain
Review model configuration default values.
The default values for model configuration parameters seem unusually high. Temperature is typically between 0 and 1, and topP is usually between 0 and 1.
🌐 Web query:
What are the typical ranges for temperature and top_p parameters in language models?💡 Result:
Temperature and Top-P are key parameters for controlling output randomness in language models. Here's a breakdown of their typical ranges:
Temperature
- Range: Typically spans 0-2 in modern LLMs[4][7][9]
- Common settings:
- <1 (e.g., 0-0.5): Produces focused, predictable outputs (ideal for technical tasks)[3][4]
- 1: Default setting maintaining original probability distribution[4]
- >1 (up to 2): Increases randomness for creative writing/exploratory tasks[9]
Value Range Use Case Examples 0-0.3 Code generation[3], factual Q&A[2] 0.4-0.7 Balanced chatbot responses[3] 0.8-2 Poetry generation[2], brainstorming[9] Top-P (Nucleus Sampling)
- Range: Always 0-1[1][5]
- Common thresholds:
- <0.5: Highly deterministic outputs (e.g., medical reports)[2]
- 0.7-0.9: Balanced creativity/reliability[1][5]
- 1: Full vocabulary consideration (rarely used)[5]
Practical combinations often pair:
- Low temp (0.2) + low Top-P (0.1) for code generation[3]
- High temp (1) + high Top-P (0.9) for creative writing[2]
Most implementations default to Temperature=1 and Top-P=1 when not specified[9], but optimal settings vary significantly by use case—experimentation is recommended[2][3].
Citations:
- 1: https://learnprompting.org/docs/intermediate/configuration_hyperparameters
- 2: https://raga.ai/blogs/llm-top-p
- 3: https://community.openai.com/t/cheat-sheet-mastering-temperature-and-top-p-in-chatgpt-api/172683
- 4: https://attri.ai/generative-ai-wiki/llm-optimization-parameters
- 5: https://promptengineering.org/prompt-engineering-with-temperature-and-top-p/
- 6: https://www.megaputer.com/mastering-language-models-a-deep-dive-into-input-parameters/
- 7: https://community.openai.com/t/does-temperature-go-to-1-or-2/174095
- 8: https://community.openai.com/t/a-better-explanation-of-top-p/2426
- 9: https://www.vellum.ai/llm-parameters/temperature
- 10: https://www.nb-data.com/p/7-llm-generation-parameters-to-know
Action: Adjust Default Values in Model Configuration
- In
src/app/(chat)/_utils/store/knowledge-store.ts(lines 27-32), the current defaults (temperature: 10andtopP: 2) are well outside conventional ranges.- Modern language models typically use a temperature within roughly 0–2 (with many defaults around 1) and a
topPstrictly between 0 and 1.- Please review and update these configuration values to ensure stable and expected behavior.
src/app/api/auth/register/route.ts (5)
11-13:
⚠️ Potential issueAdd input validation for user registration data.
The request body is processed without validating the required fields or their formats. This could lead to security vulnerabilities and data integrity issues.
Consider using a validation library like Zod or Joi:
import { z } from 'zod' const userSchema = z.object({ firstName: z.string().min(1), lastName: z.string().min(1), email: z.string().email(), password: z.string().min(8) }) const { firstName, lastName, email, password } = userSchema.parse(reqBody)
17-22:
⚠️ Potential issueUse appropriate HTTP status code for existing user.
Using 500 (Internal Server Error) for an existing user is incorrect. This should be a 409 (Conflict) status code.
- { status: 500 } + { status: 409 }📝 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 (user) { return NextResponse.json( { error: 'User with this email already Exists' }, { status: 409 }, ) }
39-40:
⚠️ Potential issueImprove JWT secret handling.
Using double non-null assertion (
!!) is unsafe. The application should fail fast if the JWT secret is not configured.- let secret: string = process.env.JWT_SEC!! + const secret = process.env.JWT_SEC + if (!secret) { + throw new Error('JWT_SEC environment variable is not configured') + }📝 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 secret = process.env.JWT_SEC if (!secret) { throw new Error('JWT_SEC environment variable is not configured') } const token = jwt.sign(data, secret)🧰 Tools
🪛 Biome (1.9.4)
[error] 39-39: Forbidden extra non-null assertion.
Safe fix: Remove extra non-null assertion.
(lint/suspicious/noExtraNonNullAssertion)
44-47:
⚠️ Potential issueImprove error handling.
Generic error messages can leak internal implementation details. Consider logging the error and returning a user-friendly message.
- return NextResponse.json( - { error: 'Internal Server Error' }, - { status: 500 } - ) + console.error('Registration error:', error) + return NextResponse.json( + { error: 'Failed to create account. Please try again later.' }, + { status: 500 } + )📝 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.error('Registration error:', error) return NextResponse.json( { error: 'Failed to create account. Please try again later.' }, { status: 500 } )
13-13:
⚠️ Potential issueRemove console.log of sensitive data.
Logging the request body could expose sensitive information like passwords in the logs.
Remove this line or replace it with sanitized logging:
- console.log(reqBody) + console.log('Processing registration for:', email)📝 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('Processing registration for:', email)src/app/(admin)/dashboard/brandsettings/page.tsx (1)
15-20:
⚠️ Potential issueAdd meaningful alt text for the image.
Empty alt text reduces accessibility. Provide a descriptive alt text for screen readers.
- alt='' + alt='Publish changes globally icon'📝 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.<Image src={`/assets/brandSettings/global.svg`} width={20} height={20} alt='Publish changes globally icon' />src/app/api/(admin)/knowledgebase/questions/ask-anything/route.ts (4)
20-25:
⚠️ Potential issueAdd file type validation.
The code doesn't validate file types, which could lead to security vulnerabilities.
const allowedTypes = ['image/png', 'image/jpeg', 'image/svg+xml']; if (!icon || !(icon instanceof File) || !allowedTypes.includes(icon.type)) { return NextResponse.json( { error: 'Invalid file type. Only PNG, JPEG, and SVG files are allowed.' }, { status: 400 } ); }
36-38:
⚠️ Potential issueSanitize file paths and use safe file names.
Using raw file names without sanitization could lead to path traversal attacks.
import { sanitizeFileName } from '@/utils/security' const safeName = sanitizeFileName(icon.name) const filePath = path.join(uploadDir, safeName)
11-15:
⚠️ Potential issueAdd file size limits.
Missing file size limits could lead to denial of service attacks.
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB if (icon.size > MAX_FILE_SIZE) { return NextResponse.json( { error: 'File size exceeds limit of 5MB' }, { status: 400 } ); }
38-38:
⚠️ Potential issueFix unsafe buffer type casting.
The current type casting is unsafe and could lead to data corruption.
- await writeFile(filePath, buffer as unknown as string | Uint8Array) + await writeFile(filePath, buffer)📝 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.await writeFile(filePath, buffer)src/app/api/(admin)/knowledgebase/questions/ask-mainefest/route.ts (4)
38-38:
⚠️ Potential issueFix Type Casting Issue with Buffer
The current type casting of buffer to string is incorrect and potentially unsafe.
- await writeFile(filePath, buffer as unknown as string | Uint8Array) + await writeFile(filePath, buffer)📝 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.await writeFile(filePath, buffer)
11-14:
⚠️ Potential issueAdd Input Validation for User and Title
The code lacks validation for user and title fields from the form data.
const form = await request.formData() const user = form.get('user') const titles = form.getAll('title') const icons = form.getAll('icon') + + if (!user || typeof user !== 'string') { + return NextResponse.json( + { error: 'Invalid user data' }, + { status: 400 }, + ) + } + + if (!titles.length || !titles.every(title => typeof title === 'string')) { + return NextResponse.json( + { error: 'Invalid title data' }, + { status: 400 }, + ) + }📝 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 form = await request.formData() const user = form.get('user') const titles = form.getAll('title') const icons = form.getAll('icon') if (!user || typeof user !== 'string') { return NextResponse.json( { error: 'Invalid user data' }, { status: 400 }, ) } if (!titles.length || !titles.every(title => typeof title === 'string')) { return NextResponse.json( { error: 'Invalid title data' }, { status: 400 }, ) }
40-47:
⚠️ Potential issueRace Condition in Database Operations
Multiple async operations without proper transaction handling could lead to inconsistent state.
- let newQuestion = await AskMainefest.create({ - user, - title, - icon: `public/knowledgebase/questions/ask-mainefest${icon.name}`, - }) - questions.push(newQuestion) - await newQuestion.save() + const session = await AskMainefest.startSession() + try { + await session.withTransaction(async () => { + const newQuestion = await AskMainefest.create([{ + user, + title, + icon: filePath, + }], { session }) + questions.push(newQuestion[0]) + }) + } finally { + await session.endSession() + }📝 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 session = await AskMainefest.startSession() try { await session.withTransaction(async () => { const newQuestion = await AskMainefest.create([{ user, title, icon: filePath, }], { session }) questions.push(newQuestion[0]) }) } finally { await session.endSession() }
30-38:
⚠️ Potential issueSecurity Risk: Unsafe File Operations in Public Directory
Writing files directly to the public directory poses several security risks:
- Path traversal attacks if filename contains
../- Overwriting existing files
- Executing malicious files through public access
Implement these security measures:
- Move uploads outside public directory
- Validate file types
- Sanitize filenames
- Add file size limits
- const uploadDir = path.join( - process.cwd(), - 'public/knowledgebase/questions/ask-mainefest', - ) + const uploadDir = path.join(process.cwd(), 'uploads/questions') + const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'] + if (!allowedTypes.includes(icon.type)) { + return NextResponse.json( + { error: 'Invalid file type' }, + { status: 400 }, + ) + } + if (icon.size > 5 * 1024 * 1024) { // 5MB limit + return NextResponse.json( + { error: 'File too large' }, + { status: 400 }, + ) + } + const sanitizedName = icon.name.replace(/[^a-zA-Z0-9.-]/g, '_') + const uniqueName = `${Date.now()}-${sanitizedName}` + const filePath = path.join(uploadDir, uniqueName)📝 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 uploadDir = path.join(process.cwd(), 'uploads/questions') const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'] if (!allowedTypes.includes(icon.type)) { return NextResponse.json( { error: 'Invalid file type' }, { status: 400 }, ) } if (icon.size > 5 * 1024 * 1024) { // 5MB limit return NextResponse.json( { error: 'File too large' }, { status: 400 }, ) } const sanitizedName = icon.name.replace(/[^a-zA-Z0-9.-]/g, '_') const uniqueName = `${Date.now()}-${sanitizedName}` const filePath = path.join(uploadDir, uniqueName) await mkdir(uploadDir, { recursive: true }) await writeFile(filePath, buffer as unknown as string | Uint8Array)src/app/api/(admin)/knowledgebase/prompt/route.ts (3)
55-61:
⚠️ Potential issueSecure Error Handling
Avoid exposing internal error details in production.
- console.error('Error in Prompt creation/update:', error.message) - - return NextResponse.json( - { error: 'Internal Server Error', details: error.message }, - { status: 500 }, - ) + console.error('Error in Prompt creation/update:', error) + + return NextResponse.json( + { error: 'Internal Server Error' }, + { status: 500 }, + )📝 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.} catch (error: any) { - console.error('Error in Prompt creation/update:', error.message) - - return NextResponse.json( - { error: 'Internal Server Error', details: error.message }, - { status: 500 }, - ) + console.error('Error in Prompt creation/update:', error) + + return NextResponse.json( + { error: 'Internal Server Error' }, + { status: 500 }, + )
8-11:
⚠️ Potential issueAdd Request Body Validation
The code lacks validation for the request body structure and types.
+ const validateModelConfig = (config: any) => { + return typeof config === 'object' && + typeof config.temperature === 'number' && + typeof config.topP === 'number' && + typeof config.frequency === 'number' && + typeof config.pressure === 'number' + } + const reqBody = await request.json() + const { prompt, preset, modelConfiguration, user } = reqBody + + if (!prompt || typeof prompt !== 'string' || + !preset || typeof preset !== 'string' || + !user || typeof user !== 'string' || + !validateModelConfig(modelConfiguration)) { + return NextResponse.json( + { error: 'Invalid request body' }, + { status: 400 }, + ) + } + await connectDB() - const { prompt, preset, modelConfiguration, user } = reqBody📝 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 validateModelConfig = (config: any) => { return typeof config === 'object' && typeof config.temperature === 'number' && typeof config.topP === 'number' && typeof config.frequency === 'number' && typeof config.pressure === 'number' } const reqBody = await request.json() const { prompt, preset, modelConfiguration, user } = reqBody if (!prompt || typeof prompt !== 'string' || !preset || typeof preset !== 'string' || !user || typeof user !== 'string' || !validateModelConfig(modelConfiguration)) { return NextResponse.json( { error: 'Invalid request body' }, { status: 400 }, ) } await connectDB()
13-37: 🛠️ Refactor suggestion
Optimize Database Operations
The current implementation performs an unnecessary find operation before update.
- const existingPrompt = await Prompt.findOne({ user }) - - if (existingPrompt) { - const updatedPrompt = await Prompt.findOneAndUpdate( - { user }, - { - $set: { - prompt, - preset, - modelConfiguration: { - temperature: modelConfiguration.temperature, - topP: modelConfiguration.topP, - frequency: modelConfiguration.frequency, - pressure: modelConfiguration.pressure, - }, - }, - }, - { new: true }, - ) + const updatedPrompt = await Prompt.findOneAndUpdate( + { user }, + { + $set: { + prompt, + preset, + modelConfiguration: { + temperature: modelConfiguration.temperature, + topP: modelConfiguration.topP, + frequency: modelConfiguration.frequency, + pressure: modelConfiguration.pressure, + }, + }, + }, + { new: true, upsert: true }, + )Committable suggestion skipped: line range outside the PR's diff.
src/app/(admin)/dashboard/brandsettings/_components/MainPreview/_components/SideBar.tsx (1)
11-11: 🛠️ Refactor suggestion
Improve Image Handling and Accessibility
- Image paths are hardcoded
- Alt text is empty
- Small image dimensions might affect quality
+const IMAGES = { + logo: { src: '/logo/logo.svg', alt: 'Company Logo' }, + chat: { src: '/assets/preview/Chat Add.svg', alt: 'New Chat Icon' }, + work: { src: '/assets/preview/Our Work.svg', alt: 'Our Work Icon' }, + team: { src: '/assets/preview/Our Team.svg', alt: 'Our Team Icon' }, + contact: { src: '/assets/preview/Contact.svg', alt: 'Contact Icon' }, +} - <Image src={`/logo/logo.svg`} alt='' width={100} height={100} /> + <Image {...IMAGES.logo} width={100} height={100} /> - <Image - src={`/assets/preview/Chat Add.svg`} - alt='' - width={15} - height={15} - /> + <Image {...IMAGES.chat} width={20} height={20} />Also applies to: 18-22, 30-35, 40-45, 49-54
src/app/(chat)/_utils/store/brand-store.ts (1)
42-79: 🛠️ Refactor suggestion
Add persistence for brand settings.
The store should persist settings to prevent loss on page refresh.
Use Zustand's persist middleware:
+import { persist } from 'zustand/middleware' -export const useBrandStore = create<State>((set) => ({ +export const useBrandStore = create( + persist<State>( + (set) => ({ // ... existing store code - })) + }), + { + name: 'brand-settings', + partialize: (state) => ({ + theme: state.theme, + fontSetting: state.fontSetting, + externalLinks: state.externalLinks, + }), + } + ) +)📝 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.import { persist } from 'zustand/middleware' import create from 'zustand' export const useBrandStore = create( persist<State>( (set) => ({ logoFile: null, theme: { description: 'AI Chat Assistance', colorAdjustments: { historyPannelBackground: '#171717', chatBackground: '#303030', chatUserBubble: '#212121', chatBotBubble: '#303030', }, }, fontSetting: { primaryFont: { fontSize: 14, fontFamily: 'system-ui', fontWeight: 400, }, secondaryFont: { fontSize: 12, fontFamily: 'system-ui', fontWeight: 400, }, chatFont: { fontSize: 16, fontFamily: 'system-ui', fontWeight: 400, }, }, externalLinks: [], setTheme: (newTheme) => set((state) => ({ theme: { ...state.theme, ...newTheme } })), setFontSetting: (newFont) => set((state) => ({ fontSetting: { ...state.fontSetting, ...newFont } })), setExternalLinks: (newLinks) => set(() => ({ externalLinks: newLinks })), setLogoFile: (newFile) => set(() => ({ logoFile: newFile })), }), { name: 'brand-settings', partialize: (state) => ({ theme: state.theme, fontSetting: state.fontSetting, externalLinks: state.externalLinks, }), } ) )src/app/(admin)/dashboard/knowledgebase/_components/KnowledegeBaseTabs/_components/KnowledegBaseQuestions.tsx (3)
14-14:
⚠️ Potential issueFix typo in component name.
The component name has a typo: "Knowledeg" should be "Knowledge".
-export default function KnowledegBaseQuestions() { +export default function KnowledgeBaseQuestions() {📝 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 KnowledgeBaseQuestions() {
49-54: 🛠️ Refactor suggestion
Remove duplicate QuestionAccordion components.
Both TabsContent sections render the same component with the same prop.
-<TabsContent value='askmainefest'> - <QuestionAccordion askAnything={askAnything} /> -</TabsContent> -<TabsContent value='askanything'> - <QuestionAccordion askAnything={askAnything} /> -</TabsContent> +<TabsContent value='askmainefest'> + <QuestionAccordion mode='mainefest' /> +</TabsContent> +<TabsContent value='askanything'> + <QuestionAccordion mode='anything' /> +</TabsContent>📝 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.<TabsContent value='askmainefest'> <QuestionAccordion mode='mainefest' /> </TabsContent> <TabsContent value='askanything'> <QuestionAccordion mode='anything' /> </TabsContent>
15-45: 🛠️ Refactor suggestion
Improve state management and button accessibility.
The current implementation has redundant state management and accessibility issues.
- Use the
valueprop from Tabs instead of a separate state:-const [askAnything, setAskAnything] = useState<boolean>(true) +const [activeTab, setActiveTab] = useState<'askmainefest' | 'askanything'>('askanything') return ( <div className='h-full w-full px-5'> - <Tabs defaultValue='askanything' className='h-full w-full px-3'> + <Tabs + value={activeTab} + onValueChange={setActiveTab} + className='h-full w-full px-3' + >
- Remove redundant buttons and improve accessibility:
-<Button - onClick={() => { - setAskAnything(!askAnything) - }} - className='w-full rounded-lg border-none bg-transparent px-0 text-black shadow-none' -> - <TabsTrigger value='askmainefest'>Ask Mainefest AI</TabsTrigger> -</Button> +<TabsTrigger + value='askmainefest' + aria-label='Switch to Ask Mainefest AI tab' +> + Ask Mainefest AI +</TabsTrigger>Committable suggestion skipped: line range outside the PR's diff.
src/models/brandSettings/BrandSettings.model.ts (3)
47-50: 🛠️ Refactor suggestion
Add validation for font weights.
Font weights should be validated to ensure they are standard values (100, 200, ..., 900).
fontWeight: { type: Number, required: true, + enum: [100, 200, 300, 400, 500, 600, 700, 800, 900], + default: 400 },Also applies to: 61-64, 75-78
19-22: 🛠️ Refactor suggestion
Fix typo in "historyPannelBackground".
The field name contains a typo: "Pannel" should be "Panel".
- historyPannelBackground: { + historyPanelBackground: { type: String, required: true, },📝 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.historyPanelBackground: { type: String, required: true, },
19-34: 🛠️ Refactor suggestion
Add validation for color values.
The color fields should validate that the values are valid CSS color strings (hex, rgb, rgba, hsl, etc.).
historyPanelBackground: { type: String, required: true, + validate: { + validator: function(v) { + return /^(#[0-9A-Fa-f]{6}|rgb\(\d{1,3},\s*\d{1,3},\s*\d{1,3}\)|rgba\(\d{1,3},\s*\d{1,3},\s*\d{1,3},\s*[0-1](\.\d+)?\))$/.test(v); + }, + message: props => `${props.value} is not a valid color value!` + } },Committable suggestion skipped: line range outside the PR's diff.
src/app/(admin)/dashboard/knowledgebase/_components/KnowledegeBaseTabs/KnowledegeBaseTabs.tsx (2)
16-22: 🛠️ Refactor suggestion
Improve image accessibility and maintainability.
The images lack meaningful alt text and use hardcoded paths.
+const ICON_PATHS = { + documents: '/assets/knowledgebase/document-text.svg', + prompts: '/assets/knowledgebase/message-programming.svg', + questions: '/assets/knowledgebase/message-question.svg', +} as const; <Image - src={`/assets/knowledgebase/document-text.svg`} - alt='' + src={ICON_PATHS.documents} + alt='Documents icon' width={20} height={20} />Also applies to: 25-31, 34-40
6-8: 🛠️ Refactor suggestion
Fix inconsistent spelling of "Knowledge".
The component and import names have inconsistent spelling of "Knowledge" ("Knowledege" vs "Knowledge").
-import KnowledegBasePrompts from './_components/KnowledegBasePrompts' -import KnowledegBaseQuestions from './_components/KnowledegBaseQuestions' -import KnowledegeBaseDocuments from './_components/KnowledegeBaseDocuments' +import KnowledgeBasePrompts from './_components/KnowledgeBasePrompts' +import KnowledgeBaseQuestions from './_components/KnowledgeBaseQuestions' +import KnowledgeBaseDocuments from './_components/KnowledgeBaseDocuments'📝 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.import KnowledgeBasePrompts from './_components/KnowledgeBasePrompts' import KnowledgeBaseQuestions from './_components/KnowledgeBaseQuestions' import KnowledgeBaseDocuments from './_components/KnowledgeBaseDocuments'src/app/(admin)/dashboard/summary/_components/Chart.tsx (1)
29-78: 🛠️ Refactor suggestion
Add type safety and improve accessibility.
The component lacks TypeScript types and accessibility features.
-const Chart = () => { +interface DataPoint { + month: string; + '2021': number; + '2020': number; + '2019': number; +} +const Chart: React.FC = () => { return ( <ResponsiveContainer width='100%' height={300}> - <AreaChart + <AreaChart + aria-label="Monthly data comparison for years 2019-2021" data={data} margin={{ top: 20, right: 30, left: 0, bottom: 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.interface DataPoint { month: string; '2021': number; '2020': number; '2019': number; } const Chart: React.FC = () => { return ( <ResponsiveContainer width='100%' height={300}> <AreaChart aria-label="Monthly data comparison for years 2019-2021" data={data} margin={{ top: 20, right: 30, left: 0, bottom: 0 }} > <defs> <linearGradient id='color2021' x1='0' y1='0' x2='0' y2='1'> <stop offset='5%' stopColor='#FBCD8E' stopOpacity={0.8} /> <stop offset='95%' stopColor='#F9F1E6' stopOpacity={0} /> </linearGradient> <linearGradient id='color2020' x1='0' y1='0' x2='0' y2='1'> <stop offset='5%' stopColor='#F9F4EC' stopOpacity={0.8} /> <stop offset='95%' stopColor='#F9F5EF' stopOpacity={0} /> </linearGradient> <linearGradient id='color2019' x1='0' y1='0' x2='0' y2='1'> <stop offset='5%' stopColor='#F9F5EF' stopOpacity={0.8} /> <stop offset='95%' stopColor='#F9F7F4' stopOpacity={0} /> </linearGradient> </defs> <XAxis dataKey='month' /> <YAxis /> <Tooltip /> <Area type='monotone' dataKey='2021' stroke='#FF7F00' fillOpacity={1} fill='url(#color2021)' /> <Area type='monotone' dataKey='2020' stroke='#FFA500' fillOpacity={1} fill='url(#color2020)' /> <Area type='monotone' dataKey='2019' stroke='#FFB347' fillOpacity={1} fill='url(#color2019)' /> </AreaChart> </ResponsiveContainer> ) }src/apis/admin/knowledgeBase.ts (1)
74-91:
⚠️ Potential issueInconsistent error handling pattern.
The
AddQuestionsfunction returns aNextResponsewhile other functions throw errors. This inconsistency could lead to confusion.export const AddQuestions = async (askAnything: boolean, data: Data) => { try { const response = await axiosInstance.post( `/api/knowledgebase/questions/${askAnything ? 'ask-anything' : 'ask-mainefest'}`, data, { headers: { 'Content-Type': 'multipart/form-data', }, }, ) return response.data } catch (error) { - return NextResponse.json( - { error: 'Internal Server Error' }, - { status: 500 }, - ) + throw new Error('Error adding questions') } }📝 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 AddQuestions = async (askAnything: boolean, data: Data) => { try { const response = await axiosInstance.post( `/api/knowledgebase/questions/${askAnything ? 'ask-anything' : 'ask-mainefest'}`, data, { headers: { 'Content-Type': 'multipart/form-data', }, }, ) return response.data } catch (error) { throw new Error('Error adding questions') } }src/app/(admin)/(auth)/login/page.tsx (2)
31-43:
⚠️ Potential issueImprove type safety and error handling in form submission.
The form submission uses
anytype and could benefit from better error handling.+type FormData = z.infer<typeof formSchema> -const onSubmit = async (data: any) => { +const onSubmit = async (data: FormData) => { try { await signIn('credentials', { email: data.email, password: data.password, redirectTo: '/dashboard/summary', }) form.reset() } catch (error) { - throw new Error('Error in The Login') + throw new Error(error instanceof Error ? error.message : 'Login 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.+type FormData = z.infer<typeof formSchema> const onSubmit = async (data: FormData) => { try { await signIn('credentials', { email: data.email, password: data.password, redirectTo: '/dashboard/summary', }) form.reset() } catch (error) { throw new Error(error instanceof Error ? error.message : 'Login failed') } }
85-90: 🛠️ Refactor suggestion
Add loading state to prevent multiple form submissions.
The submit button should be disabled during form submission to prevent duplicate requests.
+const [isSubmitting, setIsSubmitting] = useState(false) const onSubmit = async (data: FormData) => { + setIsSubmitting(true) try { // ... existing code + } finally { + setIsSubmitting(false) } } <button type='submit' + disabled={isSubmitting} - className='rounded bg-black px-4 py-2 text-white' + className='rounded bg-black px-4 py-2 text-white disabled:opacity-50' > - Submit + {isSubmitting ? 'Submitting...' : 'Submit'} </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.import React, { useState } from 'react'; export default function LoginPage() { const [isSubmitting, setIsSubmitting] = useState(false); const onSubmit = async (data: FormData) => { setIsSubmitting(true); try { // ... existing code to handle form submission } finally { setIsSubmitting(false); } }; return ( <form onSubmit={onSubmit}> {/* Other form elements */} <button type='submit' disabled={isSubmitting} className='rounded bg-black px-4 py-2 text-white disabled:opacity-50' > {isSubmitting ? 'Submitting...' : 'Submit'} </button> </form> ); }src/app/(admin)/dashboard/_components/DashboardSideBar/DashboardSideBar.tsx (2)
35-39: 🛠️ Refactor suggestion
Add error handling for signOut operation.
The logout operation should handle potential errors gracefully.
const handleClick = async () => { + try { await signOut() localStorage.removeItem('user') setUser('') + } catch (error) { + console.error('Logout failed:', error) + // Optionally show a user-friendly error message + } }📝 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 handleClick = async () => { try { await signOut() localStorage.removeItem('user') setUser('') } catch (error) { console.error('Logout failed:', error) // Optionally show a user-friendly error message } }
58-59: 🛠️ Refactor suggestion
Replace img tag with Next.js Image component for better performance.
Using the HTML
imgtag instead of Next.jsImagecomponent for static assets.- <img src={item.icon} alt='' /> + <Image + src={item.icon} + width={24} + height={24} + alt={`${item.title} icon`} + />📝 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.<Image src={item.icon} width={24} height={24} alt={`${item.title} icon`} /> <span>{item.title}</span>src/app/(admin)/dashboard/brandsettings/_components/MainPreview/_components/ChatSection.tsx (3)
65-67: 🛠️ Refactor suggestion
Use item.id instead of array index as key.
Using array indices as keys can lead to performance issues and bugs with React's reconciliation process when items are reordered or deleted.
- <SingleMessage key={i} text={item} /> + <SingleMessage key={item.id} text={item} />📝 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.{messages.map((item, i) => ( <SingleMessage key={item.id} text={item} /> ))}
72-78: 🛠️ Refactor suggestion
Add proper type for input element.
The input element is missing proper type definitions and aria-label for accessibility.
<input placeholder='Ask anything...' type='text' - name='' - id='' + name='chatInput' + id='chatInput' + aria-label='Chat message input' className='w-[90%] rounded-2xl bg-gray-100 p-1 text-xs outline-none' />📝 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='Ask anything...' type='text' name='chatInput' id='chatInput' aria-label='Chat message input' className='w-[90%] rounded-2xl bg-gray-100 p-1 text-xs outline-none' />
55-60: 🛠️ Refactor suggestion
Add alt text for better accessibility.
The Image component is missing meaningful alt text, which is important for screen readers and accessibility.
- alt='' + alt='Settings icon'📝 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.<Image src={`/assets/preview/Settings.svg`} alt='Settings icon' width={15} height={15} />{' '}src/app/(admin)/dashboard/knowledgebase/_components/KnowledegeBaseTabs/_components/KnowledegeBaseDocuments.tsx (3)
59-63:
⚠️ Potential issueAdd file size and type validation.
The file selection lacks proper validation for file size and type, which could lead to failed uploads or security issues.
onChange={(e: React.ChangeEvent<HTMLInputElement>) => { if (e.target.files?.[0]) { + const file = e.target.files[0]; + const maxSize = 10 * 1024 * 1024; // 10MB + if (file.size > maxSize) { + alert('File size must be less than 10MB'); + return; + } + if (!file.type.includes('pdf')) { + alert('Only PDF files are allowed'); + return; + } setFile(e.target.files[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.onChange={(e: React.ChangeEvent<HTMLInputElement>) => { if (e.target.files?.[0]) { const file = e.target.files[0]; const maxSize = 10 * 1024 * 1024; // 10MB if (file.size > maxSize) { alert('File size must be less than 10MB'); return; } if (!file.type.includes('pdf')) { alert('Only PDF files are allowed'); return; } setFile(e.target.files[0]) } }}
34-43:
⚠️ Potential issueAdd error handling for file upload mutation.
The mutation lacks error handling, which could lead to silent failures. Consider adding error handling and user feedback.
const { mutate, isPending, data } = useMutation({ mutationFn: async (form: FormData) => { return await fileUpload(form) }, + onError: (error) => { + console.error('Upload failed:', error); + // Add user notification here + }, onSuccess: (data) => { setFile(null) - console.log('isPending', isPending) - console.log('Success', data) + // Add success notification here }, })📝 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 { mutate, isPending, data } = useMutation({ mutationFn: async (form: FormData) => { return await fileUpload(form) }, onError: (error) => { console.error('Upload failed:', error); // Add user notification here }, onSuccess: (data) => { setFile(null) // Add success notification here }, })
29-32: 🛠️ Refactor suggestion
Add error handling for file data query.
The query lacks error handling and loading state management for the file data fetch.
- const { data: FileData, isLoading: FileLoading } = useQuery({ + const { data: FileData, isLoading: FileLoading, error } = useQuery({ queryKey: ['getAllFile'], queryFn: GetKnowledegeBaseFiles, + onError: (error) => { + console.error('Failed to fetch files:', error); + // Add user notification here + } })📝 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 { data: FileData, isLoading: FileLoading, error } = useQuery({ queryKey: ['getAllFile'], queryFn: GetKnowledegeBaseFiles, onError: (error) => { console.error('Failed to fetch files:', error); // Add user notification here } })src/app/(admin)/(auth)/token/page.tsx (3)
21-25:
⚠️ Potential issueUpdate schema to validate OpenAI API key format.
The current schema validates username instead of an API key. Update it to match OpenAI API key format.
const formSchema = z.object({ - username: z.string().min(2, { - message: 'Username must be at least 2 characters.', + apiKey: z.string().regex(/^sk-[A-Za-z0-9]{48}$/, { + message: 'Invalid OpenAI API key format. It should start with "sk-" followed by 48 characters.', }), })📝 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 formSchema = z.object({ apiKey: z.string().regex(/^sk-[A-Za-z0-9]{48}$/, { message: 'Invalid OpenAI API key format. It should start with "sk-" followed by 48 characters.', }), })
28-29:
⚠️ Potential issueImplement the onSubmit handler and add proper type safety.
The onSubmit handler is empty and the form initialization lacks proper type safety.
- const form = useForm() - function onSubmit(values: z.infer<typeof formSchema>) {} + const form = useForm<z.infer<typeof formSchema>>({ + resolver: zodResolver(formSchema), + defaultValues: { + apiKey: '', + }, + }) + + async function onSubmit(values: z.infer<typeof formSchema>) { + try { + // Add API call to save the key + // Add success notification + // Redirect to dashboard + } catch (error) { + // Add error 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.const form = useForm<z.infer<typeof formSchema>>({ resolver: zodResolver(formSchema), defaultValues: { apiKey: '', }, }) async function onSubmit(values: z.infer<typeof formSchema>) { try { // Add API call to save the key // Add success notification // Redirect to dashboard } catch (error) { // Add error handling } }
72-77:
⚠️ Potential issueMove Skip link outside the submit button.
The Skip link is incorrectly placed inside a submit button, which can lead to unexpected form submissions.
- <Button - type='submit' - className='border-1 w-1/2 border-solid border-black bg-transparent text-black' - > - <Link href={`/dashboard/summary`}>Skip</Link> - </Button> + <Link href={`/dashboard/summary`} className='w-1/2'> + <Button + type='button' + className='w-full border-1 border-solid border-black bg-transparent text-black' + > + Skip + </Button> + </Link>📝 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.<Link href={`/dashboard/summary`} className='w-1/2'> <Button type='button' className='w-full border-1 border-solid border-black bg-transparent text-black' > Skip </Button> </Link>src/app/(admin)/dashboard/brandsettings/_components/Preview.tsx (2)
36-43:
⚠️ Potential issueAdd error handling to the mutation.
The mutation lacks error handling which could lead to silent failures. Consider adding an
onErrorcallback to handle and display errors to users.const { mutate, isPending, isSuccess } = useMutation({ mutationFn: async (data: FormData) => { await AddBrandSettings(data) }, onSuccess(data, variables, context) { console.log(data) }, + onError(error) { + console.error('Failed to save brand settings:', error) + // Add toast notification or error state 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.const { mutate, isPending, isSuccess } = useMutation({ mutationFn: async (data: FormData) => { await AddBrandSettings(data) }, onSuccess(data, variables, context) { console.log(data) }, onError(error) { console.error('Failed to save brand settings:', error) // Add toast notification or error state handling }, })
74-82: 🛠️ Refactor suggestion
Improve accessibility of the Undo action button.
The image lacks meaningful alt text and the button's purpose isn't clear to screen readers.
<Button className='flex cursor-pointer items-center justify-center space-x-2 rounded-lg border-[2px] border-solid border-dashboardBorder bg-transparent text-dashboardSecondaryText shadow-none'> <Image src={`/assets/brandSettings/refresh.svg`} - alt='' + alt='Undo icon' width={20} height={20} /> - <span>Undo action</span> + <span aria-label="Undo previous changes">Undo action</span> </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.<Button className='flex cursor-pointer items-center justify-center space-x-2 rounded-lg border-[2px] border-solid border-dashboardBorder bg-transparent text-dashboardSecondaryText shadow-none'> <Image src={`/assets/brandSettings/refresh.svg`} alt='Undo icon' width={20} height={20} /> <span aria-label="Undo previous changes">Undo action</span> </Button>src/app/api/(admin)/brandsettings/route.ts (3)
95-106: 🛠️ Refactor suggestion
Add pagination to GET endpoint.
The GET endpoint fetches all brand settings without pagination, which could cause performance issues with large datasets.
-export const GET = async () => { +export const GET = async (request: NextRequest) => { try { - const themeCredentials = await BrandSetting.find() + const url = new URL(request.url) + const page = parseInt(url.searchParams.get('page') || '1') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const skip = (page - 1) * limit + const total = await BrandSetting.countDocuments() + const themeCredentials = await BrandSetting.find() + .skip(skip) + .limit(limit) + .lean() - return NextResponse.json({ themeCredentials }, { status: 200 }) + return NextResponse.json({ + themeCredentials, + pagination: { + total, + page, + pages: Math.ceil(total / limit) + } + }, { status: 200 }) } catch (error) { return NextResponse.json( { error: 'Internal Server 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.export const GET = async (request: NextRequest) => { try { const url = new URL(request.url) const page = parseInt(url.searchParams.get('page') || '1') const limit = parseInt(url.searchParams.get('limit') || '10') const skip = (page - 1) * limit const total = await BrandSetting.countDocuments() const themeCredentials = await BrandSetting.find() .skip(skip) .limit(limit) .lean() return NextResponse.json({ themeCredentials, pagination: { total, page, pages: Math.ceil(total / limit) } }, { status: 200 }) } catch (error) { return NextResponse.json( { error: 'Internal Server Error' }, { status: 500 }, ) } }
26-33:
⚠️ Potential issueValidate file path to prevent directory traversal.
The file path construction needs validation to prevent potential directory traversal attacks.
+import { basename } from 'path' + +const sanitizeFileName = (fileName: string) => { + return basename(fileName).replace(/[^a-zA-Z0-9.-]/g, '_') +} const uploadDir = path.join(process.cwd(), 'public/brandSettings/logo') await mkdir(uploadDir, { recursive: true }) -const uniqueFileName = `${Date.now()}-${logo.name}` +const uniqueFileName = `${Date.now()}-${sanitizeFileName(logo.name)}` const filePath = path.join(uploadDir, uniqueFileName)📝 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.import { basename } from 'path' const sanitizeFileName = (fileName: string) => { return basename(fileName).replace(/[^a-zA-Z0-9.-]/g, '_') } const uploadDir = path.join(process.cwd(), 'public/brandSettings/logo') await mkdir(uploadDir, { recursive: true }) const uniqueFileName = `${Date.now()}-${sanitizeFileName(logo.name)}` const filePath = path.join(uploadDir, uniqueFileName) const logoUrl = `public/brandSettings/logo/${uniqueFileName}` await writeFile(filePath, buffer as unknown as string | Uint8Array)
12-14:
⚠️ Potential issueAdd file size and type validation.
The logo file upload lacks size and type validation, which could lead to security issues.
+const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB +const ALLOWED_FILE_TYPES = ['image/jpeg', 'image/png', 'image/gif']; const form = await request.formData() const logo = form.get('logo') const data = JSON.parse(form.get('data') as string) +if (logo instanceof File) { + if (logo.size > MAX_FILE_SIZE) { + return NextResponse.json( + { error: 'File size exceeds 5MB limit.' }, + { status: 400 } + ) + } + if (!ALLOWED_FILE_TYPES.includes(logo.type)) { + return NextResponse.json( + { error: 'Invalid file type. Only JPEG, PNG, and GIF are allowed.' }, + { status: 400 } + ) + } +}📝 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 MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB const ALLOWED_FILE_TYPES = ['image/jpeg', 'image/png', 'image/gif']; const form = await request.formData() const logo = form.get('logo') const data = JSON.parse(form.get('data') as string) if (logo instanceof File) { if (logo.size > MAX_FILE_SIZE) { return NextResponse.json( { error: 'File size exceeds 5MB limit.' }, { status: 400 } ) } if (!ALLOWED_FILE_TYPES.includes(logo.type)) { return NextResponse.json( { error: 'Invalid file type. Only JPEG, PNG, and GIF are allowed.' }, { status: 400 } ) } }src/app/(admin)/dashboard/summary/_components/CircleChart.tsx (1)
80-108: 🛠️ Refactor suggestion
Add aria-label to chart for better accessibility.
The chart's label content should include ARIA attributes for screen readers.
<Label content={({ viewBox }) => { if (viewBox && 'cx' in viewBox && 'cy' in viewBox) { return ( <text x={viewBox.cx} y={viewBox.cy} textAnchor='middle' dominantBaseline='middle' + role="img" + aria-label={`Total visitors: ${totalVisitors.toLocaleString()}`} >📝 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.<Label content={({ viewBox }) => { if (viewBox && 'cx' in viewBox && 'cy' in viewBox) { return ( <text x={viewBox.cx} y={viewBox.cy} textAnchor='middle' dominantBaseline='middle' role="img" aria-label={`Total visitors: ${totalVisitors.toLocaleString()}`} > <tspan x={viewBox.cx} y={viewBox.cy} className='fill-foreground text-3xl font-bold' > {totalVisitors.toLocaleString()} </tspan> <tspan x={viewBox.cx} y={(viewBox.cy || 0) + 24} className='fill-muted-foreground' > Visitors </tspan> </text> ) } }} />src/app/(admin)/dashboard/knowledgebase/page.tsx (3)
71-78:
⚠️ Potential issueEnhance security for OpenAI key input.
The OpenAI key input should be treated as a password field and masked for security.
<input {...register('openAIKey')} - type='text' + type='password' + autoComplete='off' className='h-9 rounded-lg border-2 border-solid border-dashboardBorder p-1 text-sm outline-none' - placeholder='Paste link here...' + placeholder='Enter your OpenAI API key' />📝 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.<Label>OpenAI token</Label> <input {...register('openAIKey')} type='password' autoComplete='off' className='h-9 rounded-lg border-2 border-solid border-dashboardBorder p-1 text-sm outline-none' placeholder='Enter your OpenAI API key' /> {errors.openAIKey && <>{errors.openAIKey.message}</>}
48-48: 🛠️ Refactor suggestion
Remove console.log statement.
Remove debugging console.log statement before deploying to production.
-console.log(data)📝 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.
26-30:
⚠️ Potential issueAdd error handling to the mutation.
The mutation lacks error handling which could lead to silent failures.
const { mutate } = useMutation({ mutationFn: async (data: { user: string | null } & TUpdateSchema) => { await AddOpenAIKey(data) }, + onError: (error) => { + console.error('Failed to update OpenAI key:', error) + // Add toast notification or error state 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.const { mutate } = useMutation({ mutationFn: async (data: { user: string | null } & TUpdateSchema) => { await AddOpenAIKey(data) }, onError: (error) => { console.error('Failed to update OpenAI key:', error) // Add toast notification or error state handling } })src/app/(admin)/dashboard/knowledgebase/_components/KnowledegeBaseTabs/_components/DocuementDataTable.tsx (1)
56-58:
⚠️ Potential issueEnhance delete operation with error handling and user confirmation.
The delete operation should:
- Show a confirmation dialog
- Handle errors gracefully
- Show loading state during deletion
- Update the UI optimistically
- const handleDelete=async(id:string)=>{ - await DeleteFile(id) - } + const handleDelete = async (id: string) => { + if (!window.confirm('Are you sure you want to delete this file?')) { + return + } + try { + setTableData(prev => prev.filter(file => file._id !== id)) + await DeleteFile(id) + } catch (error) { + setTableData(prev => [...prev]) + toast({ + variant: "destructive", + title: "Error", + description: "Failed to delete file. Please try again." + }) + } + }📝 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 handleDelete = async (id: string) => { if (!window.confirm('Are you sure you want to delete this file?')) { return } try { setTableData(prev => prev.filter(file => file._id !== id)) await DeleteFile(id) } catch (error) { setTableData(prev => [...prev]) toast({ variant: "destructive", title: "Error", description: "Failed to delete file. Please try again." }) } }src/hooks/use-toast.ts (3)
134-141: 🛠️ Refactor suggestion
Consider using React's state management instead of global variables.
Managing state outside of React can lead to issues with React's reconciliation process and make the code harder to test.
Consider using React Context or a state management library like Zustand instead.
93-117: 🛠️ Refactor suggestion
Move side effects out of reducer.
The reducer contains side effects (addToRemoveQueue). Reducers should be pure functions.
Consider handling the timeout in an effect or in the action creator.
11-12: 🛠️ Refactor suggestion
Adjust TOAST_REMOVE_DELAY to a more reasonable value.
The current delay of 1000000ms (16.6 minutes) seems excessive for a toast notification.
-const TOAST_REMOVE_DELAY = 1000000 +const TOAST_REMOVE_DELAY = 5000 // 5 seconds is more typical for toasts📝 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 TOAST_LIMIT = 1 const TOAST_REMOVE_DELAY = 5000 // 5 seconds is more typical for toastssrc/app/(admin)/dashboard/summary/page.tsx (3)
31-35:
⚠️ Potential issueAdd meaningful alt text for images.
The
altattribute is empty for all images. Add descriptive alt text to improve accessibility.Apply this diff to add meaningful alt text:
- alt='' + alt='Total Users Icon'Also applies to: 55-59, 79-83, 216-220, 228-232
42-42: 🛠️ Refactor suggestion
Extract hardcoded values into constants or fetch from API.
The value "193.8K" is hardcoded and repeated multiple times. Consider extracting this into a constant or fetching from an API.
Create a constants file or integrate with an API to manage these values:
// constants.ts export const DASHBOARD_STATS = { totalUsers: '193.8K', // ... other stats }Also applies to: 66-66, 90-90, 117-117, 131-131, 145-145
26-99: 🛠️ Refactor suggestion
Reduce code duplication by creating reusable components.
The card structures and device usage sections are repeated with similar layouts. Extract these into reusable components.
Create separate components for cards and device usage:
interface StatCardProps { icon: string; label: string; value: string; trend: { value: string; type: 'positive' | 'neutral'; }; } function StatCard({ icon, label, value, trend }: StatCardProps) { return ( <div className='flex w-1/3 flex-col space-y-8 rounded-lg bg-white p-3'> <div> <Image src={`/assets/summary/${icon}`} alt={`${label} Icon`} width={40} height={40} /> </div> {/* ... rest of the card structure */} </div> ); }Also applies to: 111-153
src/app/(admin)/dashboard/brandsettings/_components/BrandAccordion.tsx (3)
35-37:
⚠️ Potential issueRemove debug console.log statements.
Remove console.log statements before pushing to production.
Apply this diff to remove the debug statements:
- console.log(theme) - console.log(fontSetting) - console.log(externalLinks) - console.log(logoFile)Also applies to: 82-82
166-166:
⚠️ Potential issueReplace 'any' type with proper event types.
The event handlers are using the 'any' type. Use proper TypeScript event types instead.
Apply this diff to fix the type safety issue:
- onChange={(e: any) => { + onChange={(e: React.ChangeEvent<HTMLInputElement>) => {Also applies to: 189-189, 236-236
275-301: 🛠️ Refactor suggestion
Extract repeated font family options into a constant.
The font family options are duplicated across three select elements. Extract them into a constant to reduce duplication and improve maintainability.
Create a constant for font options:
const FONT_FAMILIES = [ 'Poppins', 'Arial', 'Verdana', // ... other fonts ] as const; // Then in the component: {FONT_FAMILIES.map(font => ( <option key={font} value={font}>{font}</option> ))}Also applies to: 383-409, 490-516
src/app/globals.css (1)
31-31:
⚠️ Potential issueRemove duplicate CSS custom property.
The
--dashboard-buttons-bgproperty is declared twice with different values (#eaeaea and #222222). The second declaration will override the first.--dashboard-buttons-bg: #eaeaea; --dashboard-preview-bg: #eaeaea; --dashboard-preview-text: #637085; --dashboard-gray-text: #555555; --dashboard-carousel-bg: #f7f4ee; - --dashboard-buttons-bg: #222222;Also applies to: 36-36
Description
[Provide a more detailed explanation of the changes and the reason for them]
Related Issue
[Link to the related issue or ticket, if applicable]
Type of Change
How Has This Been Tested?
[Describe the steps you perform to verify your changes. Provide instructions so we can reproduce. Preferablly a LOOM would be helpful]
Checklist:
Screenshots (if appropriate):
[Add screenshots here]
Additional Notes:
[Any additional information that might be helpful for reviewers]
Summary by CodeRabbit