-
-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add onboarding ai agent #86
Changes from 10 commits
cd0fb69
0605d57
c97629d
ebfa716
bd8733e
c717def
fdd89ba
b9a3836
57fcecd
80e5fb0
a699836
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,8 @@ | |
"dev": "next dev -p 3001 --turbopack", | ||
"prebuild": "turbo --filter=@repo/db db:generate", | ||
"build": "next build", | ||
"start": "next start -p 5555", | ||
"preview": "next build && next start -p 5555", | ||
"start": "next start -p 3001", | ||
"preview": "next build && next start -p 3001", | ||
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Documentation update needed for port 3001 The port change to 3001 in the API service requires documentation updates. Our verification found that:
Please update the following:
🔗 Analysis chainDocumentation update needed for port change. Since this is a significant infrastructure change that affects local development and deployment, documentation should be updated to reflect the new port. Please ensure the following are updated:
Let's check for documentation files that might need updating: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for documentation files
fd -e md -e mdx
# Look for environment templates
fd -g '.env.example' -g '.env.template'
Length of output: 294 Script: #!/bin/bash
# Check README files for port mentions
echo "=== Checking main README.md ==="
rg -i "port|3001|3000" README.md || echo "No port mentions found"
echo -e "\n=== Checking API README ==="
rg -i "port|3001|3000" apps/api/README.md || echo "No port mentions found"
echo -e "\n=== Checking other documentation for port references ==="
rg -i "port|3001|3000" CONTRIBUTING.md || echo "No port mentions found"
echo -e "\n=== Checking for environment files ==="
fd ".env" --hidden --no-ignore
Length of output: 7840 Script: #!/bin/bash
# Let's check for any docker or docker-compose files that might reference the port
echo "=== Checking Docker files for port references ==="
fd -e dockerfile -e yml -e yaml | xargs rg -i "port.*3001|port.*3000" || echo "No port mentions found in Docker files"
# Check for any configuration files that might contain port references
echo -e "\n=== Checking common config files ==="
fd -e json -e js -e ts -g "config*" | xargs rg -i "port.*3001|port.*3000" || echo "No port mentions found in config files"
# Check specifically for Next.js config files
echo -e "\n=== Checking Next.js config files ==="
fd "next.config" | xargs rg -i "port" || echo "No port mentions found in Next.js config"
Length of output: 1115 |
||
"lint": "next lint", | ||
"lint:fix": "next lint --fix", | ||
"test": "vitest --run", | ||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,156 @@ | ||||||||||
"use server"; | ||||||||||
import { ReactNode } from "react"; | ||||||||||
import { createStreamableValue, getMutableAIState, streamUI } from "ai/rsc"; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove unused imports to clean up the code The following imports are not used and can be removed:
Apply this diff to remove unused imports: import { ReactNode } from "react";
-import { createStreamableValue, getMutableAIState, streamUI } from "ai/rsc";
+ import { getMutableAIState, streamUI } from "ai/rsc";
/* ... */
-import { Button } from "@/components/ui/button"; -import { CoreMessage, generateId, ToolInvocation } from "ai";
+import { ToolInvocation } from "ai"; Also applies to: 10-10, 14-14 🧰 Tools🪛 eslint[error] 3-3: 'createStreamableValue' is defined but never used. (@typescript-eslint/no-unused-vars) |
||||||||||
import { togetherai } from "@ai-sdk/togetherai"; | ||||||||||
import { AI } from "@/lib/ai"; | ||||||||||
import { BotMessage } from "@/components/custom/onboarding/message"; | ||||||||||
import BeatLoader from "@/components/custom/onboarding/BeatLoader"; | ||||||||||
import { getSession } from "./session"; | ||||||||||
import { z } from "zod"; | ||||||||||
import { Button } from "@/components/ui/button"; | ||||||||||
import Proceed from "@/components/custom/onboarding/proceed"; | ||||||||||
import WorkspaceForm from "@/components/custom/onboarding/workspace-form"; | ||||||||||
import {sleep } from "@/lib/utils"; | ||||||||||
import { CoreMessage, generateId,ToolInvocation } from "ai"; | ||||||||||
export type ServerMessage = { | ||||||||||
id?: number; | ||||||||||
name?: "proceed" | "workspace" ; | ||||||||||
role: "user" | "assistant"; | ||||||||||
content: string; | ||||||||||
}; | ||||||||||
|
||||||||||
export type ClientMessage = { | ||||||||||
id: number; | ||||||||||
role: "user" | "assistant"; | ||||||||||
display: ReactNode; | ||||||||||
toolInvocations?: ToolInvocation[] | ||||||||||
}; | ||||||||||
|
||||||||||
export const sendMessage = async ( | ||||||||||
message: string | ||||||||||
): Promise<ClientMessage> => { | ||||||||||
const history = getMutableAIState<typeof AI>(); | ||||||||||
console.log(history.get().length) | ||||||||||
console.log("ai",history.get()) | ||||||||||
|
||||||||||
history.update([...history.get(), { role: "user", content: message }]); | ||||||||||
|
||||||||||
const response = await streamUI({ | ||||||||||
model: togetherai("meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"), | ||||||||||
system: ` | ||||||||||
You are an onboarding assitand and you are helping users to onboard them to Plura AI. | ||||||||||
-any question not related to the onbaording should not be answered by you | ||||||||||
-if someone asks any message that is not related to the onboarding then you should respond with the exact same text "wlecome to Plura" | ||||||||||
-if the message comes as "should we continue" then call proceed tool | ||||||||||
The workflow is as follows: | ||||||||||
-User sends "yes" or "no" to proceed | ||||||||||
-If the user sends "yes" then the workflow is as follows: | ||||||||||
-then you call the workspace tool | ||||||||||
- If the user sends "no", respond with exactly: "please create a workspace to continue your onboarding" Do not call any tools for "no" | ||||||||||
- Only trigger the proceed tool when asking: "should we continue?" | ||||||||||
-If the user sends any message after workspace tool is called then you should respond with the same text:"Please create a workspace to continue" | ||||||||||
-dont call any tools if the user doesnt creates a workspace | ||||||||||
-If the message comes as workspace {workspaceName} created then respond with the exact same text "your first workspace has been created with name: {workspaceName} created" and dont call any tools | ||||||||||
`, | ||||||||||
messages: [{ role: "user", content: message }, ...history.get()], | ||||||||||
temperature: 0, | ||||||||||
initial: ( | ||||||||||
<BotMessage> | ||||||||||
<BeatLoader /> | ||||||||||
</BotMessage> | ||||||||||
), | ||||||||||
text: async function ({ content, done }) { | ||||||||||
await sleep(1000); | ||||||||||
if (done) { | ||||||||||
history.done([...history.get(), { role: "assistant", content }]); | ||||||||||
} | ||||||||||
return <BotMessage>{content}</BotMessage>; | ||||||||||
}, | ||||||||||
tools: { | ||||||||||
workspace: { | ||||||||||
description: | ||||||||||
"when the user responds with yes then render the workspace form", | ||||||||||
parameters: z.object({}), | ||||||||||
generate: async function* ({}) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using empty object patterns in Zod Using an empty object pattern If no parameters are needed, you can omit the Apply this diff: At line 74: - parameters: z.object({}),
+ // You can omit parameters or define as z.unknown() At line 98: - parameters: z.object({}),
+ // You can omit parameters or define as z.unknown() Also applies to: 98-98 🧰 Tools🪛 Biome (1.9.4)[error] 74-74: Unexpected empty object pattern. (lint/correctness/noEmptyPattern) |
||||||||||
yield ( | ||||||||||
<BotMessage> | ||||||||||
<BeatLoader /> | ||||||||||
</BotMessage> | ||||||||||
); | ||||||||||
console.log("before"); | ||||||||||
history.done([ | ||||||||||
...history.get(), | ||||||||||
{ role: "assistant", content: "workspace form rendered" }, | ||||||||||
]); | ||||||||||
console.log("history", history.get()); | ||||||||||
console.log("after"); | ||||||||||
|
||||||||||
return ( | ||||||||||
<BotMessage> | ||||||||||
<WorkspaceForm /> | ||||||||||
</BotMessage> | ||||||||||
); | ||||||||||
}, | ||||||||||
}, | ||||||||||
proceed: { | ||||||||||
description: `should we continue option that contains yes and no options`, | ||||||||||
parameters: z.object({}), | ||||||||||
generate: async function* ({}) { | ||||||||||
yield ( | ||||||||||
<BotMessage> | ||||||||||
<BeatLoader /> | ||||||||||
</BotMessage> | ||||||||||
); | ||||||||||
|
||||||||||
history.done([ | ||||||||||
...history.get(), | ||||||||||
{ role: "assistant", content: "should be continue rendered" }, | ||||||||||
]); | ||||||||||
|
||||||||||
return ( | ||||||||||
<BotMessage> | ||||||||||
<Proceed /> | ||||||||||
</BotMessage> | ||||||||||
); | ||||||||||
}, | ||||||||||
}, | ||||||||||
}, | ||||||||||
}); | ||||||||||
|
||||||||||
return { | ||||||||||
id: Date.now(), | ||||||||||
role: "assistant" as const, | ||||||||||
display: response.value, | ||||||||||
}; | ||||||||||
}; | ||||||||||
export const sendAiGreeting = async ():Promise<ClientMessage[]> => { | ||||||||||
const session= await getSession() | ||||||||||
const {name,email} = session!.user | ||||||||||
const contentString = `Hi ${name}, welcome to Plura AI!.Your email is ${email}.I am going to help you with oboarding your acccount` | ||||||||||
Comment on lines
+128
to
+129
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security: PII exposure in AI prompt The greeting message exposes user's email address to the AI model. This is unnecessary and could lead to PII leakage. - const contentString = `Hi ${name}, welcome to Plura AI!.Your email is ${email}.I am going to help you with oboarding your acccount`
+ const contentString = `Hi ${name}, welcome to Plura AI! I am going to help you with onboarding your account.` 📝 Committable suggestion
Suggested change
|
||||||||||
const history = getMutableAIState<typeof AI>(); | ||||||||||
console.log("greeting history", history.get()) | ||||||||||
const value = await streamUI({ | ||||||||||
model: togetherai("meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"), | ||||||||||
system: ` always reply the exact same text exactly as it is: ${contentString} | ||||||||||
`, | ||||||||||
messages: history.get(), | ||||||||||
initial: ( | ||||||||||
<BotMessage> | ||||||||||
<BeatLoader /> | ||||||||||
</BotMessage> | ||||||||||
), | ||||||||||
text: async function ({ content, done }) { | ||||||||||
await sleep(1000); | ||||||||||
if (done) { | ||||||||||
history.done([...history.get(), { role: "assistant", content }]); | ||||||||||
} | ||||||||||
return <BotMessage>{content}</BotMessage>; | ||||||||||
}, | ||||||||||
}); | ||||||||||
|
||||||||||
return [{ | ||||||||||
id: Date.now(), | ||||||||||
role: "assistant" as const, | ||||||||||
display: value.value, | ||||||||||
}] | ||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,17 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"use server" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { betterFetch } from "@better-fetch/fetch"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Session } from "@repo/auth"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { headers } from "next/headers"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const getSession = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const response = await betterFetch<Session>("http://localhost:3001/api/auth/get-session", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
baseURL: "http://localhost:3002", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
headers: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cookie: (await headers()).get("cookie") || "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+8
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use environment variables for API endpoints Hardcoded URLs make the code less maintainable and harder to configure across different environments. Replace hardcoded URLs with environment variables: - const response = await betterFetch<Session>("http://localhost:3001/api/auth/get-session",
- {
- baseURL: "http://localhost:3002",
+ const response = await betterFetch<Session>(
+ `${process.env.NEXT_PUBLIC_API_URL}/api/auth/get-session`,
+ {
+ baseURL: process.env.NEXT_PUBLIC_APP_URL, 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return response.data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+6
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling and improve type safety The function lacks error handling for failed requests and type validation. Consider implementing error handling: export const getSession = async () => {
+ try {
const response = await betterFetch<Session>(
// ... configuration ...
);
+ if (!response.data) {
+ throw new Error('Invalid session response');
+ }
return response.data;
+ } catch (error) {
+ console.error('Failed to fetch session:', error);
+ return null;
+ }
} 📝 Committable suggestion
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { AI } from "@/lib/ai"; | ||
|
||
export default function OnboardingLayout({children}: {children: React.ReactNode}) { | ||
return <AI>{children}</AI>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import Chatbox from "@/components/custom/onboarding/chatbox"; | ||
|
||
export default function Onboarding() { | ||
|
||
return <Chatbox /> | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,20 @@ | ||||||||||||||||||||||||
import Infobar from "@/components/custom/infobar/infobar"; | ||||||||||||||||||||||||
import ProgressBar from "@/components/custom/progress.bar"; | ||||||||||||||||||||||||
import { AppSidebar } from "@/components/custom/sidebar/sidebar"; | ||||||||||||||||||||||||
import { SidebarProvider } from "@/components/ui/sidebar"; | ||||||||||||||||||||||||
import { cookies } from "next/headers"; | ||||||||||||||||||||||||
async function RouteLayout({children}: {children: React.ReactNode}) { | ||||||||||||||||||||||||
const cookieStore = await cookies(); | ||||||||||||||||||||||||
const defaultOpen = cookieStore.get("plura-sidebar:state")?.value === "true"; | ||||||||||||||||||||||||
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for cookie access The cookie access should handle potential errors and provide fallback behavior. - const cookieStore = await cookies();
- const defaultOpen = cookieStore.get("plura-sidebar:state")?.value === "true";
+ const defaultOpen = await (async () => {
+ try {
+ const cookieStore = await cookies();
+ return cookieStore.get("plura-sidebar:state")?.value === "true";
+ } catch (error) {
+ console.error('Failed to access cookies:', error);
+ return false;
+ }
+ })(); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||
<SidebarProvider defaultOpen={defaultOpen}> | ||||||||||||||||||||||||
<AppSidebar /> | ||||||||||||||||||||||||
<div className="p-2"> | ||||||||||||||||||||||||
<ProgressBar /> | ||||||||||||||||||||||||
<Infobar /> | ||||||||||||||||||||||||
{children} | ||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||
</SidebarProvider> | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
export default RouteLayout; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,9 @@ import type { Metadata } from "next"; | |
import { GeistSans } from "geist/font/sans"; | ||
import "./globals.css"; | ||
import { ThemeProvider } from "@/hooks/theme-provider"; | ||
import { SidebarProvider } from "@/components/ui/sidebar"; | ||
import { AppSidebar } from "@/components/custom/sidebar/sidebar"; | ||
import { cookies } from "next/headers"; | ||
import Infobar from "@/components/custom/infobar/infobar"; | ||
import ProgressBar from "@/components/custom/progress.bar"; | ||
import { PosthogProvider } from "@/hooks/posthog"; | ||
|
||
import { AI } from "@/lib/ai"; | ||
import { Toaster } from "sonner"; | ||
export const metadata: Metadata = { | ||
title: "Plura", | ||
description: "Generated by create next app", | ||
|
@@ -19,8 +15,6 @@ async function RootLayout({ | |
}: Readonly<{ | ||
children: React.ReactNode; | ||
}>) { | ||
const cookieStore = await cookies(); | ||
const defaultOpen = cookieStore.get("plura-sidebar:state")?.value === "true"; | ||
|
||
return ( | ||
<html lang="en" suppressHydrationWarning> | ||
|
@@ -34,14 +28,8 @@ async function RootLayout({ | |
enableSystem | ||
disableTransitionOnChange | ||
> | ||
<SidebarProvider defaultOpen={defaultOpen}> | ||
<AppSidebar /> | ||
<div className="p-2"> | ||
<ProgressBar /> | ||
<Infobar /> | ||
{children} | ||
</div> | ||
</SidebarProvider> | ||
<Toaster /> | ||
{children} | ||
Comment on lines
+31
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Warning: Inconsistent Toaster implementations across layouts The Toaster components in the two layout files are using different implementations:
This inconsistency could lead to different toast notification behaviors across the applications. 🔗 Analysis chainLGTM! Clean layout structure The simplified layout with the Toaster component is well-structured. The removal of the sidebar-related complexity makes the code more maintainable. Let's verify if the Toaster component is consistently used across other layouts: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Check for consistent Toaster usage across layouts
# Expect: Other layout files should also use Toaster for consistency
# Search for other layout files and check Toaster usage
fd "layout.tsx" apps/ --exec rg -l "Toaster"
Length of output: 90 Script: #!/bin/bash
# Let's check the actual implementation of Toaster in both layout files
rg -A 5 -B 5 "Toaster" apps/app/app/layout.tsx apps/www/app/layout.tsx
Length of output: 2372 |
||
</ThemeProvider> | ||
</body> | ||
</PosthogProvider> | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,27 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"use client"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { motion } from "motion/react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect import path The import from 'motion/react' is incorrect. It should be from 'framer-motion'. -import { motion } from "motion/react";
+import { motion } from "framer-motion"; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export default function BeatLoader() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="flex backdrop:space-x-1"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{[0, 1, 2].map((index) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<motion.div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
key={index} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className="w-3 h-3 bg-muted rounded-full" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
animate={{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
scale: [1, 0.5, 1], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
opacity: [1, 0.5, 1], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
transition={{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
duration: 0.6, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
repeat: Infinity, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
repeatType: "loop", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ease: "easeInOut", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
delay: index * 0.2, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+5
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance component accessibility and customization The loader component could benefit from several improvements:
-export default function BeatLoader() {
+interface BeatLoaderProps {
+ color?: string;
+ size?: number;
+ speed?: number;
+}
+
+export default function BeatLoader({
+ color = 'bg-muted',
+ size = 3,
+ speed = 0.6
+}: BeatLoaderProps) {
return (
- <div className="flex backdrop:space-x-1">
+ <div
+ role="status"
+ aria-label="Loading"
+ className="flex backdrop:space-x-1"
+ >
{[0, 1, 2].map((index) => (
<motion.div
key={index}
- className="w-3 h-3 bg-muted rounded-full"
+ className={`w-${size} h-${size} ${color} rounded-full`}
animate={{
scale: [1, 0.5, 1],
opacity: [1, 0.5, 1],
}}
transition={{
- duration: 0.6,
+ duration: speed,
repeat: Infinity,
repeatType: "loop",
ease: "easeInOut",
- delay: index * 0.2,
+ delay: index * (speed / 3),
}}
/>
))}
+ <span className="sr-only">Loading...</span>
</div>
);
} 📝 Committable suggestion
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { Textarea } from "@/components/ui/textarea"; | ||
import {ArrowUp} from "lucide-react"; | ||
|
||
export function ChatInput() { | ||
return ( | ||
<div className="fixed inset-x-0 w-full bottom-4 "> | ||
<div className="max-w-2xl mx-auto "> | ||
<form> | ||
<div className="grow border border-card flex flex-col justify-center items-center rounded-2xl bg-card p-1 shadow-md "> | ||
<Textarea | ||
id="textarea-17" | ||
className="resize-none placeholder:text-neutral-600" | ||
placeholder="Leave a comment" | ||
/> | ||
Comment on lines
+8
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add form submission handling and state management. The form lacks essential functionality:
- <form>
+ <form onSubmit={handleSubmit}>
<div className="grow border border-card flex flex-col justify-center items-center rounded-2xl bg-card p-1 shadow-md ">
<Textarea
id="textarea-17"
+ value={message}
+ onChange={(e) => setMessage(e.target.value)}
className="resize-none placeholder:text-neutral-600"
placeholder="Leave a comment"
+ aria-label="Chat message input"
/>
|
||
|
||
<div className=" px-2 self-end group"> | ||
<div className="p-1 rounded-md bg-woodsmoke-700 border border-neutral-700"> | ||
<ArrowUp | ||
size={20} | ||
strokeWidth={2} | ||
aria-hidden="true" | ||
className="text-neutral-500 group-hover:text-neutral-200 " | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Unresolved merge conflict markers detected
The file contains unresolved Git merge conflict markers. This will cause syntax errors and break the application. Please resolve the merge conflict before proceeding.
Remove the following lines:
🧰 Tools
🪛 Biome (1.9.4)
[error] 17-19: Expected a statement but instead found '<<<<<<< HEAD:apps/api/app/api/[[...route]]/route.ts
======='.
Expected a statement here.
(parse)