From 9718940258dcf16b8955ce369a1a996153b96ecc Mon Sep 17 00:00:00 2001 From: asepharyana Date: Mon, 3 Aug 2026 06:44:23 +0700 Subject: [PATCH] =?UTF-8?q?fix(chatbot):=20FAB=20opens=20chat=20directly?= =?UTF-8?q?=20=E2=80=94=20remove=20extra=20toggle=20+=20UX=20polish?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - chatbot-container: remove chatOpen layer — the minimized bubble now expands straight into the chat panel (single click, no extra button) - Remove the redundant 'Tanya soal server...' quick-prompt button and the PanelLeft collapse toggle (one less state to fight) - Bubble fixed h-[460px], chat panel flex-fills remaining space - chat-panel: suggestion chips on empty state (suasana server, channel paling ramai, total pesan, pesan bermasalah) so first-time users can start with a single click - Input: roomier padding, more descriptive placeholder, bigger send button, autoComplete off - Drop chatOpen/setChatOpen from context (dead state) --- .../src/components/chatbot/chat-panel.tsx | 47 +++++++++++++---- .../components/chatbot/chatbot-container.tsx | 52 +++++-------------- .../components/chatbot/chatbot-context.tsx | 7 --- 3 files changed, 50 insertions(+), 56 deletions(-) diff --git a/services/frontend/src/components/chatbot/chat-panel.tsx b/services/frontend/src/components/chatbot/chat-panel.tsx index 6006d87..272b411 100644 --- a/services/frontend/src/components/chatbot/chat-panel.tsx +++ b/services/frontend/src/components/chatbot/chat-panel.tsx @@ -1,6 +1,6 @@ "use client"; -import { Eraser, Send } from "lucide-react"; +import { Eraser, Send, Sparkles } from "lucide-react"; import { useEffect, useRef } from "react"; import { useChatbot } from "./chatbot-context"; @@ -17,6 +17,13 @@ function formatTime(ts: string): string { }); } +const SUGGESTIONS = [ + "Gimana suasana server hari ini?", + "Channel mana yang paling ramai?", + "Total pesan di server?", + "Ada pesan bermasalah?", +]; + export function ChatPanel({ inputRef: externalInputRef }: ChatPanelProps) { const { messages, sendMessage, clearMessages, isTyping } = useChatbot(); const listRef = useRef(null); @@ -39,21 +46,37 @@ export function ChatPanel({ inputRef: externalInputRef }: ChatPanelProps) { input.value = ""; }; + const handleSuggestion = (text: string) => { + if (isTyping) return; + sendMessage(text); + }; + return (
{/* Chat messages */}
{messages.length === 0 ? ( -
-

+

+

Halo! 👋 Aku tau soal server ini — pesan, flag, dan aktivitas.

-

- Coba tanya: "Gimana suasana server hari ini?" -

+
+ {SUGGESTIONS.map((s) => ( + + ))} +
) : ( messages.map((msg, i) => ( @@ -101,14 +124,15 @@ export function ChatPanel({ inputRef: externalInputRef }: ChatPanelProps) { {/* Input bar */}
{messages.length > 0 && (
diff --git a/services/frontend/src/components/chatbot/chatbot-container.tsx b/services/frontend/src/components/chatbot/chatbot-container.tsx index 4919a41..343d056 100644 --- a/services/frontend/src/components/chatbot/chatbot-container.tsx +++ b/services/frontend/src/components/chatbot/chatbot-container.tsx @@ -1,12 +1,12 @@ "use client"; -import { Bot, MessageCircle, Minimize2, PanelLeft } from "lucide-react"; +import { Bot, Minimize2 } from "lucide-react"; import { useCallback, useEffect, useRef, useState } from "react"; import { ChatPanel } from "./chat-panel"; import { useChatbot } from "./chatbot-context"; export function ChatbotContainer() { - const { minimized, setMinimized, chatOpen, setChatOpen } = useChatbot(); + const { minimized, setMinimized } = useChatbot(); const [position, setPosition] = useState({ x: 0, y: 0 }); const [dragging, setDragging] = useState(false); const [dragStart, setDragStart] = useState({ x: 0, y: 0 }); @@ -32,11 +32,11 @@ export function ChatbotContainer() { // Focus input when chat opens useEffect(() => { - if (chatOpen) { + if (!minimized) { const id = setTimeout(() => inputRef.current?.focus(), 150); return () => clearTimeout(id); } - }, [chatOpen]); + }, [minimized]); return ( // biome-ignore lint/a11y/noStaticElementInteractions: drag container — mouse-move gesture surface, not keyboard-interactive content @@ -47,12 +47,11 @@ export function ChatbotContainer() { onMouseUp={handleMouseUp} onMouseLeave={handleMouseUp} > - {/* Main chatbot bubble */} + {/* Main chatbot bubble — minimized FAB opens the full chat directly */}
{minimized ? ( ) : ( - <> +
{/* Drag handle + controls */} {/* biome-ignore lint/a11y/noStaticElementInteractions: drag handle — mouse-only gesture, keyboard users use the buttons in this header */}
@@ -77,47 +77,23 @@ export function ChatbotContainer() { Chatbot
-
- {/* Chat panel (expandable) */} -
+ {/* Chat panel — always open when bubble is expanded */} +
- - {/* Quick prompt row when chat is closed */} - {!chatOpen && ( - - )} - +
)}
diff --git a/services/frontend/src/components/chatbot/chatbot-context.tsx b/services/frontend/src/components/chatbot/chatbot-context.tsx index 86398b5..986d1c7 100644 --- a/services/frontend/src/components/chatbot/chatbot-context.tsx +++ b/services/frontend/src/components/chatbot/chatbot-context.tsx @@ -35,10 +35,6 @@ interface ChatbotContextValue { minimized: boolean; setMinimized: (v: boolean) => void; - /** Whether the chat panel inside the bubble is open */ - chatOpen: boolean; - setChatOpen: (v: boolean) => void; - /** * @deprecated Use `minimized` / `setMinimized` instead. * Legacy toggle alias kept for compatibility. @@ -63,7 +59,6 @@ const ChatbotContext = createContext(null); export function ChatbotProvider({ children }: { children: ReactNode }) { const [expression, setExpression] = useState("idle"); const [minimized, setMinimized] = useState(true); - const [chatOpen, setChatOpen] = useState(false); const [messages, setMessages] = useState([]); const [isTyping, setIsTyping] = useState(false); const [guildId, setGuildId] = useState(""); @@ -168,8 +163,6 @@ export function ChatbotProvider({ children }: { children: ReactNode }) { setExpression, minimized, setMinimized, - chatOpen, - setChatOpen, isOpen, setOpen, toggle,