2023-03-07 13:19:56 -05:00
|
|
|
import React, { useState, useRef } from 'react';
|
2023-03-06 21:43:49 -05:00
|
|
|
import { useSelector } from 'react-redux';
|
2023-03-03 21:33:09 -05:00
|
|
|
import { DropdownMenuRadioItem } from '../ui/DropdownMenu.tsx';
|
2023-03-07 13:19:56 -05:00
|
|
|
import { Circle } from 'lucide-react';
|
2023-03-03 21:33:09 -05:00
|
|
|
import { DialogTrigger } from '../ui/Dialog.tsx';
|
2023-03-06 21:43:49 -05:00
|
|
|
import RenameButton from '../Conversations/RenameButton';
|
|
|
|
|
import TrashIcon from '../svg/TrashIcon';
|
2023-03-07 13:19:56 -05:00
|
|
|
import manualSWR from '~/utils/fetchers';
|
2023-03-03 21:33:09 -05:00
|
|
|
|
2023-03-07 13:19:56 -05:00
|
|
|
export default function ModelItem({ modelName, value, onSelect }) {
|
|
|
|
|
const { customModel } = useSelector((state) => state.submit);
|
2023-03-06 21:43:49 -05:00
|
|
|
const { initial } = useSelector((state) => state.models);
|
|
|
|
|
const [isHovering, setIsHovering] = useState(false);
|
2023-03-07 13:19:56 -05:00
|
|
|
const [renaming, setRenaming] = useState(false);
|
|
|
|
|
const [currentName, setCurrentName] = useState(modelName);
|
|
|
|
|
const [modelInput, setModelInput] = useState(modelName);
|
|
|
|
|
const inputRef = useRef(null);
|
2023-03-10 21:06:13 +08:00
|
|
|
const rename = manualSWR(`/api/customGpts`, 'post');
|
|
|
|
|
const deleteCustom = manualSWR(`/api/customGpts/delete`, 'post');
|
2023-03-06 21:43:49 -05:00
|
|
|
|
2023-03-03 21:33:09 -05:00
|
|
|
if (value === 'chatgptCustom') {
|
|
|
|
|
return (
|
|
|
|
|
<DialogTrigger className="w-full">
|
|
|
|
|
<DropdownMenuRadioItem
|
|
|
|
|
value={value}
|
2023-03-06 21:43:49 -05:00
|
|
|
className="dark:font-semibold dark:text-gray-100 dark:hover:bg-gray-800"
|
2023-03-03 21:33:09 -05:00
|
|
|
>
|
|
|
|
|
{modelName}
|
|
|
|
|
<sup>$</sup>
|
|
|
|
|
</DropdownMenuRadioItem>
|
|
|
|
|
</DialogTrigger>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 13:19:56 -05:00
|
|
|
if (initial[value]) {
|
|
|
|
|
return (
|
|
|
|
|
<DropdownMenuRadioItem
|
|
|
|
|
value={value}
|
|
|
|
|
className="dark:font-semibold dark:text-gray-100 dark:hover:bg-gray-800"
|
|
|
|
|
>
|
|
|
|
|
{modelName}
|
|
|
|
|
{value === 'chatgpt' && <sup>$</sup>}
|
|
|
|
|
</DropdownMenuRadioItem>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-06 21:43:49 -05:00
|
|
|
const handleMouseOver = () => {
|
|
|
|
|
setIsHovering(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleMouseOut = () => {
|
|
|
|
|
setIsHovering(false);
|
|
|
|
|
};
|
|
|
|
|
|
2023-03-07 13:19:56 -05:00
|
|
|
const renameHandler = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setRenaming(true);
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
inputRef.current.focus();
|
|
|
|
|
}, 25);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onRename = (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
setRenaming(false);
|
|
|
|
|
if (modelInput === modelName) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
rename.trigger({
|
|
|
|
|
prevLabel: currentName,
|
|
|
|
|
chatGptLabel: modelInput,
|
|
|
|
|
value: modelInput.toLowerCase()
|
|
|
|
|
});
|
|
|
|
|
setCurrentName(modelInput);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onDelete = async (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
await deleteCustom.trigger({ value: currentName.toLowerCase() });
|
|
|
|
|
// await mutate();
|
|
|
|
|
onSelect('chatgpt', true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleKeyDown = (e) => {
|
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
|
onRename(e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-03-06 21:43:49 -05:00
|
|
|
const buttonClass = {
|
|
|
|
|
className:
|
2023-03-07 13:19:56 -05:00
|
|
|
'z-50 rounded-md m-0 text-gray-400 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const itemClass = {
|
|
|
|
|
className:
|
|
|
|
|
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none hover:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:hover:bg-slate-700 dark:font-semibold dark:text-gray-100 dark:hover:bg-gray-800'
|
2023-03-06 21:43:49 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const showButtons = isHovering && !initial[value];
|
|
|
|
|
|
2023-03-03 21:33:09 -05:00
|
|
|
return (
|
2023-03-07 13:19:56 -05:00
|
|
|
<span
|
2023-03-03 21:33:09 -05:00
|
|
|
value={value}
|
2023-03-07 13:19:56 -05:00
|
|
|
className={itemClass.className}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
onSelect(value, true);
|
|
|
|
|
}}
|
2023-03-06 21:43:49 -05:00
|
|
|
onMouseOver={handleMouseOver}
|
|
|
|
|
onMouseOut={handleMouseOut}
|
2023-03-03 21:33:09 -05:00
|
|
|
>
|
2023-03-07 13:19:56 -05:00
|
|
|
{customModel === value && (
|
|
|
|
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
|
|
|
<Circle className="h-2 w-2 fill-current" />
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
{renaming === true ? (
|
|
|
|
|
<input
|
|
|
|
|
ref={inputRef}
|
|
|
|
|
type="text"
|
|
|
|
|
className="pointer-events-auto z-50 m-0 mr-2 w-3/4 border border-blue-500 bg-transparent p-0 text-sm leading-tight outline-none"
|
|
|
|
|
value={modelInput}
|
|
|
|
|
onClick={(e) => e.stopPropagation()}
|
|
|
|
|
onChange={(e) => setModelInput(e.target.value)}
|
|
|
|
|
onBlur={onRename}
|
|
|
|
|
onKeyDown={handleKeyDown}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
modelInput
|
|
|
|
|
)}
|
2023-03-06 21:43:49 -05:00
|
|
|
|
2023-03-07 13:19:56 -05:00
|
|
|
{value === 'chatgpt' && <sup>$</sup>}
|
2023-03-06 21:43:49 -05:00
|
|
|
{showButtons && (
|
|
|
|
|
<>
|
2023-03-07 13:19:56 -05:00
|
|
|
<RenameButton
|
|
|
|
|
twcss={`ml-auto mr-2 ${buttonClass.className}`}
|
|
|
|
|
onRename={onRename}
|
|
|
|
|
renaming={renaming}
|
|
|
|
|
renameHandler={renameHandler}
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
{...buttonClass}
|
|
|
|
|
onClick={onDelete}
|
|
|
|
|
>
|
2023-03-06 21:43:49 -05:00
|
|
|
<TrashIcon />
|
|
|
|
|
</button>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
2023-03-07 13:19:56 -05:00
|
|
|
</span>
|
2023-03-03 21:33:09 -05:00
|
|
|
);
|
|
|
|
|
}
|