| @@ -1,7 +1,9 @@ | ||
| 1 | 1 | import { sparkle } from '@agent/icons'; |
| 2 | +import { useDomainActivities } from '@agent/state/domain-activities'; | |
| 2 | 3 | import { useSuggestionsStore } from '@agent/state/suggestions'; |
| 3 | -import { useState } from '@wordpress/element'; | |
| 4 | +import { track } from '@shared/lib/track'; | |
| 5 | +import { useEffect, useState } from '@wordpress/element'; | |
| 4 | 6 | import { __ } from '@wordpress/i18n'; |
| 5 | 7 | import { |
| 6 | 8 | chevronRight, |
| 7 | 9 | drafts, |
| @@ -30,17 +32,26 @@ | ||
| 30 | 32 | }; |
| 31 | 33 | |
| 32 | 34 | export const ChatSuggestions = ({ suggestions }) => { |
| 33 | 35 | const { markAsClicked, isAvailable, getSuggestions } = useSuggestionsStore(); |
| 36 | + const { setDomainActivity } = useDomainActivities(); | |
| 34 | 37 | const [allSuggestions, setAllSuggestions] = useState(suggestions); |
| 35 | 38 | |
| 36 | - const handleSubmit = (suggestion) => { | |
| 39 | + const handleSelect = (suggestion) => { | |
| 40 | + markAsClicked(suggestion); | |
| 41 | + if (suggestion.telemetry) { | |
| 42 | + track(suggestion.telemetry.key, suggestion.telemetry.payload); | |
| 43 | + } else if (suggestion.tracking) { | |
| 44 | + setDomainActivity({ ...suggestion.tracking, action: 'clicked' }); | |
| 45 | + } | |
| 46 | + // External-link suggestions are plain links: the anchor opens the new tab. | |
| 47 | + // They don't trigger a workflow or post a message in the chat. | |
| 48 | + if (suggestion.type === 'external-link') return; | |
| 37 | 49 | window.dispatchEvent( |
| 38 | 50 | new CustomEvent('extendify-agent:chat-submit', { |
| 39 | 51 | detail: { message: suggestion.message }, |
| 40 | 52 | }), |
| 41 | 53 | ); |
| 42 | - markAsClicked(suggestion); | |
| 43 | 54 | }; |
| 44 | 55 | |
| 45 | 56 | const handleShowMore = () => { |
| 46 | 57 | const next = getSuggestions({ slice: 6, exclude: allSuggestions }); |
| @@ -57,9 +68,9 @@ | ||
| 57 | 68 | return ( |
| 58 | 69 | <SuggestionButton |
| 59 | 70 | key={suggestion.message} |
| 60 | 71 | suggestion={suggestion} |
| 61 | - handleSubmit={handleSubmit} | |
| 72 | + onSelect={handleSelect} | |
| 62 | 73 | /> |
| 63 | 74 | ); |
| 64 | 75 | })} |
| 65 | 76 | <ShowMoreButton handleShowMore={handleShowMore} /> |
| @@ -66,16 +77,25 @@ | ||
| 66 | 77 | </> |
| 67 | 78 | ); |
| 68 | 79 | }; |
| 69 | 80 | |
| 70 | -const SuggestionButton = ({ suggestion, handleSubmit }) => { | |
| 81 | +const SuggestionButton = ({ suggestion, onSelect }) => { | |
| 82 | + const { setDomainActivity } = useDomainActivities(); | |
| 71 | 83 | const icon = icons[suggestion?.icon] ?? icons.sparkle; |
| 72 | - return ( | |
| 73 | - <button | |
| 74 | - type="button" | |
| 75 | - className="group flex items-center justify-between rounded-sm bg-transparent px-1 py-1 text-left text-sm not-italic text-gray-900 transition-colors duration-100 hover:bg-gray-100 focus:outline-hidden focus:ring-2 focus:ring-design-main" | |
| 76 | - onClick={() => handleSubmit(suggestion)} | |
| 77 | - > | |
| 84 | + | |
| 85 | + useEffect(() => { | |
| 86 | + if (suggestion.viewTelemetry) { | |
| 87 | + track(suggestion.viewTelemetry.key, suggestion.viewTelemetry.payload); | |
| 88 | + } | |
| 89 | + if (suggestion.tracking) { | |
| 90 | + setDomainActivity({ ...suggestion.tracking, action: 'viewed' }); | |
| 91 | + } | |
| 92 | + }, [suggestion, setDomainActivity]); | |
| 93 | + | |
| 94 | + const className = | |
| 95 | + 'group flex items-center justify-between rounded-sm bg-transparent px-1 py-1 text-left text-sm not-italic text-gray-900 transition-colors duration-100 hover:bg-gray-100 focus:outline-hidden focus:ring-2 focus:ring-design-main'; | |
| 96 | + const content = ( | |
| 97 | + <> | |
| 78 | 98 | <div className="flex items-center gap-1.5 leading-none"> |
| 79 | 99 | <span className="h-5 w-5 shrink-0 self-start fill-gray-700"> |
| 80 | 100 | {icon} |
| 81 | 101 | </span> |
| @@ -83,8 +103,33 @@ | ||
| 83 | 103 | </div> |
| 84 | 104 | <span className="inline-block h-5 w-5 fill-gray-700 leading-none opacity-0 transition-opacity duration-100 group-hover:opacity-100 rtl:scale-x-[-1]"> |
| 85 | 105 | {chevronRight} |
| 86 | 106 | </span> |
| 107 | + </> | |
| 108 | + ); | |
| 109 | + | |
| 110 | + // External-link suggestions render as a real anchor that opens in a new tab. | |
| 111 | + if (suggestion.type === 'external-link') { | |
| 112 | + return ( | |
| 113 | + <a | |
| 114 | + href={suggestion.url} | |
| 115 | + target="_blank" | |
| 116 | + rel="noopener noreferrer" | |
| 117 | + className={`${className} no-underline`} | |
| 118 | + onClick={() => onSelect(suggestion)} | |
| 119 | + > | |
| 120 | + {content} | |
| 121 | + </a> | |
| 122 | + ); | |
| 123 | + } | |
| 124 | + | |
| 125 | + return ( | |
| 126 | + <button | |
| 127 | + type="button" | |
| 128 | + className={className} | |
| 129 | + onClick={() => onSelect(suggestion)} | |
| 130 | + > | |
| 131 | + {content} | |
| 87 | 132 | </button> |
| 88 | 133 | ); |
| 89 | 134 | }; |
| 90 | 135 | |