PluginProbe
Extendify / 3.1.0
Extendify v3.1.0
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Agent / components / ChatSuggestions.jsx

ChatSuggestions.jsx in Extendify 3.1.0, at src/Agent/components/ChatSuggestions.jsx

144 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { sparkle } from '@agent/icons';
2 import { useDomainActivities } from '@agent/state/domain-activities';
3 import { useSuggestionsStore } from '@agent/state/suggestions';
4 import { useState } from '@wordpress/element';
5 import { __ } from '@wordpress/i18n';
6 import {
7 chevronRight,
8 drafts,
9 help,
10 pencil,
11 published,
12 siteLogo,
13 styles,
14 swatch,
15 typography,
16 video,
17 } from '@wordpress/icons';
18
19 const icons = {
20 styles,
21 edit: pencil,
22 help,
23 video,
24 sparkle,
25 drafts,
26 published,
27 typography,
28 pencil,
29 siteLogo,
30 swatch,
31 };
32
33 export const ChatSuggestions = ({ suggestions }) => {
34 const { markAsClicked, isAvailable, getSuggestions } = useSuggestionsStore();
35 const { setDomainActivity } = useDomainActivities();
36 const [allSuggestions, setAllSuggestions] = useState(suggestions);
37
38 const handleSelect = (suggestion) => {
39 markAsClicked(suggestion);
40 if (suggestion.tracking) {
41 setDomainActivity({ ...suggestion.tracking, action: 'clicked' });
42 }
43 // External-link suggestions are plain links: the anchor opens the new tab.
44 // They don't trigger a workflow or post a message in the chat.
45 if (suggestion.type === 'external-link') return;
46 window.dispatchEvent(
47 new CustomEvent('extendify-agent:chat-submit', {
48 detail: { message: suggestion.message },
49 }),
50 );
51 };
52
53 const handleShowMore = () => {
54 const next = getSuggestions({ slice: 6, exclude: allSuggestions });
55 setAllSuggestions((prev) => [...prev, ...next]);
56 };
57
58 if (!suggestions) return null;
59
60 return (
61 <>
62 {allSuggestions.map((suggestion) => {
63 // Hide them if it's not available to the user
64 if (!isAvailable(suggestion)) return null;
65 return (
66 <SuggestionButton
67 key={suggestion.message}
68 suggestion={suggestion}
69 onSelect={handleSelect}
70 />
71 );
72 })}
73 <ShowMoreButton handleShowMore={handleShowMore} />
74 </>
75 );
76 };
77
78 const SuggestionButton = ({ suggestion, onSelect }) => {
79 const icon = icons[suggestion?.icon] ?? icons.sparkle;
80 const className =
81 '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';
82 const content = (
83 <>
84 <div className="flex items-center gap-1.5 leading-none">
85 <span className="h-5 w-5 shrink-0 self-start fill-gray-700">
86 {icon}
87 </span>
88 <span className="leading-5">{suggestion.message}</span>
89 </div>
90 <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]">
91 {chevronRight}
92 </span>
93 </>
94 );
95
96 // External-link suggestions render as a real anchor that opens in a new tab.
97 if (suggestion.type === 'external-link') {
98 return (
99 <a
100 href={suggestion.url}
101 target="_blank"
102 rel="noopener noreferrer"
103 className={`${className} no-underline`}
104 onClick={() => onSelect(suggestion)}
105 >
106 {content}
107 </a>
108 );
109 }
110
111 return (
112 <button
113 type="button"
114 className={className}
115 onClick={() => onSelect(suggestion)}
116 >
117 {content}
118 </button>
119 );
120 };
121
122 const ShowMoreButton = ({ handleShowMore }) => {
123 const [hide, setHide] = useState(false);
124 const handleClick = () => {
125 handleShowMore();
126 setHide(true);
127 };
128
129 if (hide) return null;
130 return (
131 <button
132 type="button"
133 className="group flex w-full items-center gap-3 rounded-sm bg-transparent px-1 py-1 text-xs not-italic text-gray-800 transition-colors duration-100 hover:text-gray-900 focus:outline-hidden group"
134 onClick={handleClick}
135 >
136 <span className="h-px flex-1 bg-gray-200" />
137 <span className="group-hover:underline group-focus:ring-2 group-focus:ring-design-main">
138 {__('Show more', 'extendify-local')}
139 </span>
140 <span className="h-px flex-1 bg-gray-200" />
141 </button>
142 );
143 };
144