diff --git a/surfsense_web/components/assistant-ui/thread.tsx b/surfsense_web/components/assistant-ui/thread.tsx
index a41d2e143..5b4e430d7 100644
--- a/surfsense_web/components/assistant-ui/thread.tsx
+++ b/surfsense_web/components/assistant-ui/thread.tsx
@@ -21,7 +21,9 @@ import {
RefreshCwIcon,
SquareIcon,
} from "lucide-react";
+import Image from "next/image";
import type { FC } from "react";
+import { useAtomValue } from "jotai";
import {
ComposerAddAttachment,
ComposerAttachments,
@@ -32,6 +34,7 @@ import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
+import { currentUserAtom } from "@/atoms/user/user-query.atoms";
export const Thread: FC = () => {
return (
@@ -59,7 +62,11 @@ export const Thread: FC = () => {
-
+ !thread.isEmpty}>
+
+
+
+
@@ -80,62 +87,109 @@ const ThreadScrollToBottom: FC = () => {
);
};
-const ThreadWelcome: FC = () => {
- return (
-
-
-
-
- Hello there!
-
-
- How can I help you today?
-
-
-
-
-
- );
+const getTimeBasedGreeting = (userEmail?: string): string => {
+ const hour = new Date().getHours();
+
+ // Extract first name from email if available
+ const firstName = userEmail
+ ? userEmail.split("@")[0].split(".")[0].charAt(0).toUpperCase() +
+ userEmail.split("@")[0].split(".")[0].slice(1)
+ : null;
+
+ // Array of greeting variations for each time period
+ const morningGreetings = [
+ "Good morning",
+ "Rise and shine",
+ "Morning",
+ "Hey there",
+ "Welcome back",
+ ];
+
+ const afternoonGreetings = [
+ "Good afternoon",
+ "Afternoon",
+ "Hey there",
+ "Welcome back",
+ "Hope you're having a great day",
+ ];
+
+ const eveningGreetings = [
+ "Good evening",
+ "Evening",
+ "Hey there",
+ "Welcome back",
+ "Hope you had a great day",
+ ];
+
+ const nightGreetings = [
+ "Late night",
+ "Still up",
+ "Hey there",
+ "Welcome back",
+ "Burning the midnight oil",
+ ];
+
+ // Select a random greeting based on time
+ let greeting: string;
+ if (hour < 12) {
+ greeting = morningGreetings[Math.floor(Math.random() * morningGreetings.length)];
+ } else if (hour < 17) {
+ greeting = afternoonGreetings[Math.floor(Math.random() * afternoonGreetings.length)];
+ } else if (hour < 21) {
+ greeting = eveningGreetings[Math.floor(Math.random() * eveningGreetings.length)];
+ } else {
+ greeting = nightGreetings[Math.floor(Math.random() * nightGreetings.length)];
+ }
+
+ // Add personalization with first name if available
+ if (firstName) {
+ return `${greeting}, ${firstName}!`;
+ }
+
+ return `${greeting}!`;
};
-const SUGGESTIONS = [
- {
- title: "What's the weather",
- label: "in San Francisco?",
- prompt: "What's the weather in San Francisco?",
- },
- {
- title: "Explain React hooks",
- label: "like useState and useEffect",
- prompt: "Explain React hooks like useState and useEffect",
- },
-] as const;
-
-const ThreadSuggestions: FC = () => {
+const ThreadWelcome: FC = () => {
+ const { data: user } = useAtomValue(currentUserAtom);
+
return (
-
- {SUGGESTIONS.map((suggestion, index) => (
-
-
-
-
-
- ))}
+
+ {/* Greeting positioned near the composer */}
+
+
+ {/** biome-ignore lint/a11y/noStaticElementInteractions: wrong lint error, this is a workaround to fix the lint error */}
+
{
+ const rect = e.currentTarget.getBoundingClientRect();
+ const x = (e.clientX - rect.left - rect.width / 2) / 3;
+ const y = (e.clientY - rect.top - rect.height / 2) / 3;
+ e.currentTarget.style.setProperty("--mag-x", `${x}px`);
+ e.currentTarget.style.setProperty("--mag-y", `${y}px`);
+ }}
+ onMouseLeave={(e) => {
+ e.currentTarget.style.setProperty("--mag-x", "0px");
+ e.currentTarget.style.setProperty("--mag-y", "0px");
+ }}
+ >
+
+
+ {getTimeBasedGreeting(user?.email)}
+
+
+ {/* Composer centered in the middle of the screen */}
+
+
+
);
};
@@ -143,10 +197,10 @@ const ThreadSuggestions: FC = () => {
const Composer: FC = () => {
return (
-
+
{
})
);
+ // Check if composer text is empty
+ const isComposerEmpty = useAssistantState(({ composer }) => {
+ const text = composer.text?.trim() || "";
+ return text.length === 0;
+ });
+
+ const isSendDisabled = hasProcessingAttachments || isComposerEmpty;
+
return (
@@ -183,19 +245,25 @@ const ComposerAction: FC = () => {
)}
!thread.isRunning}>
-
+