import { useState, useId, useCallback, useMemo, useRef } from 'react'; import { useRecoilValue } from 'recoil'; import * as Ariakit from '@ariakit/react'; import { BookmarkPlusIcon } from 'lucide-react'; import { useQueryClient } from '@tanstack/react-query'; import { Constants, QueryKeys } from 'librechat-data-provider'; import { BookmarkFilledIcon, BookmarkIcon } from '@radix-ui/react-icons'; import type { TConversationTag } from 'librechat-data-provider'; import type { FC } from 'react'; import type * as t from '~/common'; import { useConversationTagsQuery, useTagConversationMutation } from '~/data-provider'; import { DropdownPopup, TooltipAnchor } from '~/components/ui'; import { BookmarkContext } from '~/Providers/BookmarkContext'; import { BookmarkEditDialog } from '~/components/Bookmarks'; import { useBookmarkSuccess, useLocalize } from '~/hooks'; import { NotificationSeverity } from '~/common'; import { useToastContext } from '~/Providers'; import { Spinner } from '~/components'; import { cn, logger } from '~/utils'; import store from '~/store'; const BookmarkMenu: FC = () => { const localize = useLocalize(); const queryClient = useQueryClient(); const { showToast } = useToastContext(); const conversation = useRecoilValue(store.conversationByIndex(0)) || undefined; const conversationId = conversation?.conversationId ?? ''; const updateConvoTags = useBookmarkSuccess(conversationId); const tags = conversation?.tags; const isTemporary = conversation?.expiredAt != null; const menuId = useId(); const [isMenuOpen, setIsMenuOpen] = useState(false); const [isDialogOpen, setIsDialogOpen] = useState(false); const mutation = useTagConversationMutation(conversationId, { onSuccess: (newTags: string[], vars) => { updateConvoTags(newTags); const tagElement = document.getElementById(vars.tag); console.log('tagElement', tagElement); if (tagElement) { setTimeout(() => tagElement.focus(), 2); } }, onError: () => { showToast({ message: 'Error adding bookmark', severity: NotificationSeverity.ERROR, }); }, onMutate: (vars) => { const tagElement = document.getElementById(vars.tag); console.log('tagElement', tagElement); if (tagElement) { setTimeout(() => tagElement.focus(), 2); } }, }); const { data } = useConversationTagsQuery(); const isActiveConvo = Boolean( conversation && conversationId && conversationId !== Constants.NEW_CONVO && conversationId !== 'search', ); const handleSubmit = useCallback( (tag?: string) => { if (tag === undefined || tag === '' || !conversationId) { showToast({ message: 'Invalid tag or conversationId', severity: NotificationSeverity.ERROR, }); return; } logger.log('tag_mutation', 'BookmarkMenu - handleSubmit: tags before setting', tags); const allTags = queryClient.getQueryData([QueryKeys.conversationTags]) ?? []; const existingTags = allTags.map((t) => t.tag); const filteredTags = tags?.filter((t) => existingTags.includes(t)); logger.log('tag_mutation', 'BookmarkMenu - handleSubmit: tags after filtering', filteredTags); const newTags = filteredTags?.includes(tag) === true ? filteredTags.filter((t) => t !== tag) : [...(filteredTags ?? []), tag]; logger.log('tag_mutation', 'BookmarkMenu - handleSubmit: tags after', newTags); mutation.mutate({ tags: newTags, tag, }); }, [tags, conversationId, mutation, queryClient, showToast], ); const newBookmarkRef = useRef(null); const dropdownItems: t.MenuItemProps[] = useMemo(() => { const items: t.MenuItemProps[] = [ { id: '%___new___bookmark___%', label: localize('com_ui_bookmarks_new'), icon: , hideOnClick: false, ref: newBookmarkRef, render: (props) =>