diff --git a/apps/desktop/src/components/editor-area/text-selection-popover.tsx b/apps/desktop/src/components/editor-area/text-selection-popover.tsx index 87c6516899..67255e9ff2 100644 --- a/apps/desktop/src/components/editor-area/text-selection-popover.tsx +++ b/apps/desktop/src/components/editor-area/text-selection-popover.tsx @@ -2,6 +2,9 @@ import { Button } from "@hypr/ui/components/ui/button"; import { MessageSquare, Sparkles } from "lucide-react"; import { useEffect, useRef, useState } from "react"; +import { useHypr } from "@/contexts"; +import { commands as analyticsCommands } from "@hypr/plugin-analytics"; + interface TextSelectionPopoverProps { isEnhancedNote: boolean; onAnnotate: (selectedText: string, selectedRect: DOMRect) => void; @@ -19,6 +22,7 @@ export function TextSelectionPopover( ) { const [selection, setSelection] = useState(null); const delayTimeoutRef = useRef(); + const { userId } = useHypr(); useEffect(() => { if (!isEnhancedNote) { @@ -91,6 +95,11 @@ export function TextSelectionPopover( } const handleAnnotateClick = () => { + analyticsCommands.event({ + event: "source_view_clicked", + distinct_id: userId, + }); + onAnnotate(selection.text, selection.rect); setSelection(null); // Hide the popover }; diff --git a/apps/desktop/src/components/settings/views/template.tsx b/apps/desktop/src/components/settings/views/template.tsx index 34c627d400..44273b58ae 100644 --- a/apps/desktop/src/components/settings/views/template.tsx +++ b/apps/desktop/src/components/settings/views/template.tsx @@ -13,7 +13,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "@hypr/ui/components/ui/ import { Textarea } from "@hypr/ui/components/ui/textarea"; import { Trans, useLingui } from "@lingui/react/macro"; import { CopyIcon, MoreHorizontalIcon, TrashIcon } from "lucide-react"; -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { SectionsList } from "../components/template-sections"; interface TemplateEditorProps { @@ -94,36 +94,41 @@ export default function TemplateEditor({ return title.replace(/^(\p{Emoji})\s*/u, ""); }; + // Local state for both inputs + const [titleText, setTitleText] = useState(() => getTitleWithoutEmoji(template.title || "")); + const [descriptionText, setDescriptionText] = useState(template.description || ""); const [selectedEmoji, setSelectedEmoji] = useState(() => extractEmojiFromTitle(template.title || "")); - const [emojiPopoverOpen, setEmojiPopoverOpen] = useState(false); - const handleChangeTitle = useCallback( - (e: React.ChangeEvent) => { - const titleWithoutEmoji = e.target.value; - const fullTitle = selectedEmoji + " " + titleWithoutEmoji; - onTemplateUpdate({ ...template, title: fullTitle }); - }, - [onTemplateUpdate, template, selectedEmoji], - ); + // Sync local state when template ID changes (new template loaded) + useEffect(() => { + setTitleText(getTitleWithoutEmoji(template.title || "")); + setDescriptionText(template.description || ""); + setSelectedEmoji(extractEmojiFromTitle(template.title || "")); + }, [template.id]); - const handleEmojiSelect = useCallback( - (emoji: string) => { - setSelectedEmoji(emoji); - const titleWithoutEmoji = getTitleWithoutEmoji(template.title || ""); - const fullTitle = emoji + " " + titleWithoutEmoji; - onTemplateUpdate({ ...template, title: fullTitle }); - setEmojiPopoverOpen(false); - }, - [onTemplateUpdate, template], - ); + // Simple handlers with local state + const handleChangeTitle = (e: React.ChangeEvent) => { + const newTitle = e.target.value; + setTitleText(newTitle); // Update local state immediately - const handleChangeDescription = useCallback( - (e: React.ChangeEvent) => { - onTemplateUpdate({ ...template, description: e.target.value }); - }, - [onTemplateUpdate, template], - ); + const fullTitle = selectedEmoji + " " + newTitle; + onTemplateUpdate({ ...template, title: fullTitle }); + }; + + const handleEmojiSelect = (emoji: string) => { + setSelectedEmoji(emoji); + const fullTitle = emoji + " " + titleText; // Use local state + onTemplateUpdate({ ...template, title: fullTitle }); + setEmojiPopoverOpen(false); + }; + + const handleChangeDescription = (e: React.ChangeEvent) => { + const newDescription = e.target.value; + setDescriptionText(newDescription); // Update local state immediately + + onTemplateUpdate({ ...template, description: newDescription }); + }; const handleChangeSections = useCallback( (sections: Template["sections"]) => { @@ -145,7 +150,7 @@ export default function TemplateEditor({
- {/* Emoji Selector */} + {/* Emoji Selector - unchanged */}
- {/* Menu Button - Show for all templates with different options */} {isCreator && ( @@ -228,7 +231,7 @@ export default function TemplateEditor({