import { ChatbotUIContext } from "@/context/context" import { Tables } from "@/supabase/types" import { FC, useContext, useEffect, useRef, useState } from "react" import { Button } from "../ui/button" import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog" import { Label } from "../ui/label" import { TextareaAutosize } from "../ui/textarea-autosize" import { usePromptAndCommand } from "./chat-hooks/use-prompt-and-command" interface PromptPickerProps {} export const PromptPicker: FC = ({}) => { const { prompts, isPromptPickerOpen, setIsPromptPickerOpen, focusPrompt, slashCommand } = useContext(ChatbotUIContext) const { handleSelectPrompt } = usePromptAndCommand() const itemsRef = useRef<(HTMLDivElement | null)[]>([]) const [promptVariables, setPromptVariables] = useState< { promptId: string name: string value: string }[] >([]) const [showPromptVariables, setShowPromptVariables] = useState(false) useEffect(() => { if (focusPrompt && itemsRef.current[0]) { itemsRef.current[0].focus() } }, [focusPrompt]) const [isTyping, setIsTyping] = useState(false) const filteredPrompts = prompts.filter(prompt => prompt.name.toLowerCase().includes(slashCommand.toLowerCase()) ) const handleOpenChange = (isOpen: boolean) => { setIsPromptPickerOpen(isOpen) } const callSelectPrompt = (prompt: Tables<"prompts">) => { const regex = /\{\{.*?\}\}/g const matches = prompt.content.match(regex) if (matches) { const newPromptVariables = matches.map(match => ({ promptId: prompt.id, name: match.replace(/\{\{|\}\}/g, ""), value: "" })) setPromptVariables(newPromptVariables) setShowPromptVariables(true) } else { handleSelectPrompt(prompt) handleOpenChange(false) } } const getKeyDownHandler = (index: number) => (e: React.KeyboardEvent) => { if (e.key === "Backspace") { e.preventDefault() handleOpenChange(false) } else if (e.key === "Enter") { e.preventDefault() callSelectPrompt(filteredPrompts[index]) } else if ( (e.key === "Tab" || e.key === "ArrowDown") && !e.shiftKey && index === filteredPrompts.length - 1 ) { e.preventDefault() itemsRef.current[0]?.focus() } else if (e.key === "ArrowUp" && !e.shiftKey && index === 0) { // go to last element if arrow up is pressed on first element e.preventDefault() itemsRef.current[itemsRef.current.length - 1]?.focus() } else if (e.key === "ArrowUp") { e.preventDefault() const prevIndex = index - 1 >= 0 ? index - 1 : itemsRef.current.length - 1 itemsRef.current[prevIndex]?.focus() } else if (e.key === "ArrowDown") { e.preventDefault() const nextIndex = index + 1 < itemsRef.current.length ? index + 1 : 0 itemsRef.current[nextIndex]?.focus() } } const handleSubmitPromptVariables = () => { const newPromptContent = promptVariables.reduce( (prevContent, variable) => prevContent.replace( new RegExp(`\\{\\{${variable.name}\\}\\}`, "g"), variable.value ), prompts.find(prompt => prompt.id === promptVariables[0].promptId) ?.content || "" ) const newPrompt: any = { ...prompts.find(prompt => prompt.id === promptVariables[0].promptId), content: newPromptContent } handleSelectPrompt(newPrompt) handleOpenChange(false) setShowPromptVariables(false) setPromptVariables([]) } const handleCancelPromptVariables = () => { setShowPromptVariables(false) setPromptVariables([]) } const handleKeydownPromptVariables = ( e: React.KeyboardEvent ) => { if (!isTyping && e.key === "Enter" && !e.shiftKey) { e.preventDefault() handleSubmitPromptVariables() } } return ( <> {isPromptPickerOpen && (
{showPromptVariables ? ( Enter Prompt Variables
{promptVariables.map((variable, index) => (
{ const newPromptVariables = [...promptVariables] newPromptVariables[index].value = value setPromptVariables(newPromptVariables) }} minRows={3} maxRows={5} onCompositionStart={() => setIsTyping(true)} onCompositionEnd={() => setIsTyping(false)} />
))}
) : filteredPrompts.length === 0 ? (
No matching prompts.
) : ( filteredPrompts.map((prompt, index) => (
{ itemsRef.current[index] = ref }} tabIndex={0} className="hover:bg-accent focus:bg-accent flex cursor-pointer flex-col rounded p-2 focus:outline-none" onClick={() => callSelectPrompt(prompt)} onKeyDown={getKeyDownHandler(index)} >
{prompt.name}
{prompt.content}
)) )}
)} ) }