PluginProbe
Extendify / 1.9.3
Extendify v1.9.3
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 0.7.0 All 126 releases
extendify / src / Chat / components / ChatDialog.js

ChatDialog.js in Extendify 1.9.3, at src/Chat/components/ChatDialog.js

166 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useState } from '@wordpress/element'
2 import { __ } from '@wordpress/i18n'
3 import { Icon } from '@wordpress/icons'
4 import { getAnswer } from '@chat/api/Data'
5 import { updateUserMeta } from '@chat/api/Data'
6 import { Answer } from '@chat/components/dialog/Answer'
7 import { Header } from '@chat/components/dialog/Header'
8 import { History } from '@chat/components/dialog/History'
9 import { Question } from '@chat/components/dialog/Question'
10 import { Support } from '@chat/components/dialog/Support'
11 import { useHistoryStore } from '@chat/state/Global'
12 import { history } from '@chat/svg/index'
13
14 export const ChatDialog = ({ setShowChat }) => {
15 const [question, setQuestion] = useState(undefined)
16 const [answer, setAnswer] = useState(undefined)
17 const [answerId, setAnswerId] = useState(undefined)
18 const [error, setError] = useState(false)
19 const [experienceLevel, setExperienceLevel] = useState(
20 window.extChatData?.experienceLevel ?? 'beginner',
21 )
22 const [showHistory, setShowHistory] = useState(false)
23 const { hasHistory } = useHistoryStore()
24
25 const showAIConsent = window.extChatData?.showAIConsent
26 const consentTermsUrl = window.extChatData?.consentTermsUrl
27 const userId = window.extChatData?.userId
28 const [userGaveConsent, setUserGaveConsent] = useState(
29 window.extChatData?.userGaveConsent,
30 )
31
32 const userAcceptsTerms = () => {
33 updateUserMeta(userId, 'extendify_ai_consent', true)
34 setUserGaveConsent(true)
35 }
36
37 const reset = () => {
38 setQuestion(undefined)
39 setAnswer(undefined)
40 setAnswerId(undefined)
41 setError(false)
42 setAnswerId(undefined)
43 setShowHistory(false)
44 }
45
46 const handleSubmit = async (formSubmitEvent) => {
47 formSubmitEvent.preventDefault()
48 const q = formSubmitEvent.target?.[0]?.value ?? ''
49 if (!q) return
50 setAnswer('...')
51 setQuestion(q)
52 const response = await getAnswer({ question: q, experienceLevel })
53 if (!response.ok) {
54 setError(true)
55 return
56 }
57 try {
58 const reader = response.body.getReader()
59 const decoder = new TextDecoder()
60 while (true) {
61 const { value, done } = await reader.read()
62 if (done) break
63 const chunk = decoder.decode(value)
64 try {
65 const { id } = JSON.parse(chunk)
66 if (!id) throw new Error('False positive')
67 setAnswerId(id)
68 } catch (e) {
69 // if chunk fails to parse then it's a string
70 setAnswer((v) => {
71 if (v === '...') return chunk
72 return v + chunk
73 })
74 }
75 }
76 } catch (e) {
77 console.error(e)
78 }
79 }
80
81 return (
82 <div className="fixed z-high overflow-hidden w-80 bottom-24 right-6 border border-solid border-gray-300 text-base bg-white rounded-lg shadow-2xl">
83 <div className="p-6 bg-design-main text-design-text">
84 <Header
85 question={question}
86 reset={reset}
87 experienceLevel={experienceLevel}
88 setExperienceLevel={setExperienceLevel}
89 showHistory={showHistory}
90 setShowChat={setShowChat}
91 />
92 {!answer && !question && !showHistory && (
93 <Question onSubmit={handleSubmit} />
94 )}
95 </div>
96
97 {!answer && !question && !showHistory && (
98 <Support height={hasHistory() ? 'h-11' : 'h-32'} />
99 )}
100
101 {question && !showHistory && (
102 <Answer
103 question={question}
104 answer={answer}
105 answerId={answerId}
106 reset={reset}
107 error={error}
108 />
109 )}
110
111 {showHistory && <History reset={reset} />}
112
113 {!answer && !question && hasHistory() && !showHistory && (
114 <div className="text-xs p-6 border border-b-0 border-r-0 border-l-0 border-solid border-gray-300 text-gray-600 flex justify-around">
115 <div
116 className="flex flex-col items-center group cursor-pointer"
117 onClick={() => setShowHistory(true)}>
118 <span>
119 <Icon
120 icon={history}
121 className={
122 'group-hover:text-design-main cursor-pointer w-5 h-5 text-gray-500 fill-current'
123 }
124 />
125 </span>
126 <span className="group-hover:text-design-main">
127 {__('Recent History', 'extendify')}
128 </span>
129 </div>
130 </div>
131 )}
132
133 {showAIConsent && !userGaveConsent && (
134 <div className="bg-black bg-opacity-75 rounded p-6 absolute inset-0 flex items-center justify-center">
135 <div className="bg-white p-4 rounded">
136 <h2 className="text-lg mt-0 mb-2">
137 {__('Terms of Use', 'extendify')}
138 </h2>
139 <p className="m-0">
140 {
141 // translators: at the end of the sentence, there is a link to the terms of use
142 __(
143 'In order to use the AI-powered chatbot to answer your WordPress questions, you must agree to the terms of use. For more information, click on this link:',
144 'extendify',
145 )
146 }{' '}
147 <a
148 href={consentTermsUrl}
149 target="_blank"
150 rel="noreferrer">
151 {__('Terms of Use', 'extendify')}
152 </a>
153 </p>
154 <button
155 className="mt-4 bg-wp-theme-500 text-white rounded px-4 py-2 border-0 text-center w-full cursor-pointer"
156 type="button"
157 onClick={() => userAcceptsTerms()}>
158 {__('Accept', 'extendify')}
159 </button>
160 </div>
161 </div>
162 )}
163 </div>
164 )
165 }
166