PluginProbe
Extendify / 1.6.1
Extendify v1.6.1
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 / Chat / components / dialog / Answer.js

Answer.js in Extendify 1.6.1, at src/Chat/components/dialog/Answer.js

119 lines 4.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { Fragment, useEffect, useRef, useState } from '@wordpress/element'
2 import { __ } from '@wordpress/i18n'
3 import { Icon } from '@wordpress/icons'
4 import { Error } from '@chat/components/dialog/Error'
5 import { useAnswer } from '@chat/hooks/useAnswer'
6 import { robot, send } from '@chat/svg'
7 import classnames from 'classnames'
8
9 export const Answer = ({
10 question,
11 reset,
12 answerId,
13 questionLoading,
14 questionError,
15 }) => {
16 const [status, setStatus] = useState(null)
17 const [displayedAnswer, setDisplayedAnswer] = useState('')
18 const { data, error } = useAnswer(answerId ?? null, status)
19 const { answer, loading, status: answerStatus } = data ?? {}
20 const scrollRef = useRef(null)
21
22 useEffect(() => setStatus(answerStatus), [answerStatus])
23
24 useEffect(() => {
25 if (!answer) return
26 const words = answer.slice(displayedAnswer.length).trim().split(' ')
27 const nextWord = words[0]
28 if (!nextWord) return
29 const retryTime = [75, 75, 75, 150, 300].at(
30 Math.floor(Math.random() * 5),
31 )
32 const timer = setTimeout(() => {
33 setDisplayedAnswer((prev) => prev + (prev ? ' ' : '') + nextWord)
34 if (scrollRef.current) {
35 scrollRef.current.scrollTo({
36 top: scrollRef.current.scrollHeight,
37 behavior: 'smooth',
38 })
39 }
40 }, retryTime)
41 return () => clearTimeout(timer)
42 }, [answer, status, displayedAnswer])
43
44 return (
45 <>
46 <div className="p-6 pb-10 h-80 overflow-scroll" ref={scrollRef}>
47 <div className="flex justify-end mb-8 ml-4 relative">
48 {questionError ? (
49 <Error
50 text={__(
51 'Oops! We were unable to send your question.',
52 'extendify',
53 )}
54 reset={reset}
55 />
56 ) : (
57 <p className="m-0 p-5 rounded-lg bg-gray-800 text-design-text text-sm">
58 <span
59 className={classnames({
60 'animate-pulse': questionLoading,
61 })}>
62 {question}
63 </span>
64 </p>
65 )}
66 </div>
67 {(status || loading || error) && (
68 <div className="flex justify-start mr-4 relative">
69 <div className="absolute -mt-4 -ml-2 rounded-full bg-design-main p-2 flex items-center">
70 <Icon
71 icon={robot}
72 className="text-design-text fill-current w-4 h-4"
73 />
74 </div>
75 {error ? (
76 <Error
77 text={__(
78 'Oops! We encountered an error while processing your question.',
79 'extendify',
80 )}
81 reset={reset}
82 />
83 ) : (
84 <p className="m-0 p-5 rounded-lg bg-gray-100 text-gray-800 text-sm">
85 {displayedAnswer ? (
86 displayedAnswer
87 .split('\n')
88 .map((line, index) => (
89 <Fragment key={index}>
90 {line}
91 <br />
92 </Fragment>
93 ))
94 ) : (
95 <span className="text-gray-600 font-bold animate-pulse">
96 ...
97 </span>
98 )}
99 </p>
100 )}
101 </div>
102 )}
103 </div>
104 <div className="ask-another-question p-6 relative flex justify-center">
105 <button
106 type="button"
107 onClick={reset}
108 className="bg-design-main text-design-text border-none py-2 px-4 rounded-sm cursor-pointer text-sm flex items-center gap-2">
109 {__('Ask Another Question', 'extendify')}
110 <Icon
111 icon={send}
112 className="text-design-text fill-current h-6"
113 />
114 </button>
115 </div>
116 </>
117 )
118 }
119