|
import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react'; |
|
|
|
import { Prompt } from '@/types/prompt'; |
|
|
|
interface Props { |
|
prompt: Prompt; |
|
variables: string[]; |
|
onSubmit: (updatedVariables: string[]) => void; |
|
onClose: () => void; |
|
} |
|
|
|
export const VariableModal: FC<Props> = ({ |
|
prompt, |
|
variables, |
|
onSubmit, |
|
onClose, |
|
}) => { |
|
const [updatedVariables, setUpdatedVariables] = useState< |
|
{ key: string; value: string }[] |
|
>( |
|
variables |
|
.map((variable) => ({ key: variable, value: '' })) |
|
.filter( |
|
(item, index, array) => |
|
array.findIndex((t) => t.key === item.key) === index, |
|
), |
|
); |
|
|
|
const modalRef = useRef<HTMLDivElement>(null); |
|
const nameInputRef = useRef<HTMLTextAreaElement>(null); |
|
|
|
const handleChange = (index: number, value: string) => { |
|
setUpdatedVariables((prev) => { |
|
const updated = [...prev]; |
|
updated[index].value = value; |
|
return updated; |
|
}); |
|
}; |
|
|
|
const handleSubmit = () => { |
|
if (updatedVariables.some((variable) => variable.value === '')) { |
|
alert('Please fill out all variables'); |
|
return; |
|
} |
|
|
|
onSubmit(updatedVariables.map((variable) => variable.value)); |
|
onClose(); |
|
}; |
|
|
|
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => { |
|
if (e.key === 'Enter' && !e.shiftKey) { |
|
e.preventDefault(); |
|
handleSubmit(); |
|
} else if (e.key === 'Escape') { |
|
onClose(); |
|
} |
|
}; |
|
|
|
useEffect(() => { |
|
const handleOutsideClick = (e: MouseEvent) => { |
|
if (modalRef.current && !modalRef.current.contains(e.target as Node)) { |
|
onClose(); |
|
} |
|
}; |
|
|
|
window.addEventListener('click', handleOutsideClick); |
|
|
|
return () => { |
|
window.removeEventListener('click', handleOutsideClick); |
|
}; |
|
}, [onClose]); |
|
|
|
useEffect(() => { |
|
if (nameInputRef.current) { |
|
nameInputRef.current.focus(); |
|
} |
|
}, []); |
|
|
|
return ( |
|
<div |
|
className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50" |
|
onKeyDown={handleKeyDown} |
|
> |
|
<div |
|
ref={modalRef} |
|
className="dark:border-netural-400 inline-block max-h-[400px] transform overflow-y-auto rounded-lg border border-gray-300 bg-white px-4 pt-5 pb-4 text-left align-bottom shadow-xl transition-all dark:bg-[#202123] sm:my-8 sm:max-h-[600px] sm:w-full sm:max-w-lg sm:p-6 sm:align-middle" |
|
role="dialog" |
|
> |
|
<div className="mb-4 text-xl font-bold text-black dark:text-neutral-200"> |
|
{prompt.name} |
|
</div> |
|
|
|
<div className="mb-4 text-sm italic text-black dark:text-neutral-200"> |
|
{prompt.description} |
|
</div> |
|
|
|
{updatedVariables.map((variable, index) => ( |
|
<div className="mb-4" key={index}> |
|
<div className="mb-2 text-sm font-bold text-neutral-200"> |
|
{variable.key} |
|
</div> |
|
|
|
<textarea |
|
ref={index === 0 ? nameInputRef : undefined} |
|
className="mt-1 w-full rounded-lg border border-neutral-500 px-4 py-2 text-neutral-900 shadow focus:outline-none dark:border-neutral-800 dark:border-opacity-50 dark:bg-[#40414F] dark:text-neutral-100" |
|
style={{ resize: 'none' }} |
|
placeholder={`Enter a value for ${variable.key}...`} |
|
value={variable.value} |
|
onChange={(e) => handleChange(index, e.target.value)} |
|
rows={3} |
|
/> |
|
</div> |
|
))} |
|
|
|
<button |
|
className="mt-6 w-full rounded-lg border border-neutral-500 px-4 py-2 text-neutral-900 shadow hover:bg-neutral-100 focus:outline-none dark:border-neutral-800 dark:border-opacity-50 dark:bg-white dark:text-black dark:hover:bg-neutral-300" |
|
onClick={handleSubmit} |
|
> |
|
Submit |
|
</button> |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|