From b7e348264a39d978b53cde98ce0b31a220d07f08 Mon Sep 17 00:00:00 2001 From: 0xd22f9c Date: Wed, 28 Aug 2024 13:35:11 +0700 Subject: [PATCH 01/41] fx --- src/components/MagicIcon/index.tsx | 43 ++++ .../Buy/studio/ButtonStartChat/index.tsx | 31 +++ .../studio/ButtonStartChat/styles.module.scss | 27 +++ .../Chatbox/Actions/ButtonClsoe/index.tsx | 28 +++ .../Actions/ButtonClsoe/styles.module.scss | 5 + .../blockchains/Buy/studio/Chatbox/index.tsx | 185 ++++++++++++++++++ .../Buy/studio/Chatbox/styles.module.scss | 157 +++++++++++++++ .../blockchains/Buy/studio/WorkArea/index.tsx | 2 + 8 files changed, 478 insertions(+) create mode 100644 src/components/MagicIcon/index.tsx create mode 100644 src/modules/blockchains/Buy/studio/ButtonStartChat/index.tsx create mode 100644 src/modules/blockchains/Buy/studio/ButtonStartChat/styles.module.scss create mode 100644 src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonClsoe/index.tsx create mode 100644 src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonClsoe/styles.module.scss create mode 100644 src/modules/blockchains/Buy/studio/Chatbox/index.tsx create mode 100644 src/modules/blockchains/Buy/studio/Chatbox/styles.module.scss diff --git a/src/components/MagicIcon/index.tsx b/src/components/MagicIcon/index.tsx new file mode 100644 index 000000000..57a8adf5a --- /dev/null +++ b/src/components/MagicIcon/index.tsx @@ -0,0 +1,43 @@ +import { ReactElement } from 'react'; + +export default function MagicIcon({ + color, +}: { + color: 'white' | 'black'; +}): ReactElement { + return ( +
+ + + + + + + + + + + + + +
+ ); +} diff --git a/src/modules/blockchains/Buy/studio/ButtonStartChat/index.tsx b/src/modules/blockchains/Buy/studio/ButtonStartChat/index.tsx new file mode 100644 index 000000000..b6c9c44be --- /dev/null +++ b/src/modules/blockchains/Buy/studio/ButtonStartChat/index.tsx @@ -0,0 +1,31 @@ +import MagicIcon from '@/components/MagicIcon'; +import { gsap } from 'gsap'; +import { ReactElement, useState } from 'react'; +import Chatbox from '../Chatbox'; +import styles from './styles.module.scss'; + +export default function ButtonStartChat(): ReactElement { + const [isChatboxOpen, setIsChatboxOpen] = useState(false); + + const handleOpenChatbox = () => { + setIsChatboxOpen(true); + gsap.fromTo( + '.chatbox-container', + { x: '100%' }, + { x: '0%', duration: 0.5, ease: 'power2.out' } + ); + }; + + return ( + <> + + {isChatboxOpen && ( +
+ +
+ )} + + ); +} \ No newline at end of file diff --git a/src/modules/blockchains/Buy/studio/ButtonStartChat/styles.module.scss b/src/modules/blockchains/Buy/studio/ButtonStartChat/styles.module.scss new file mode 100644 index 000000000..5e6d48469 --- /dev/null +++ b/src/modules/blockchains/Buy/studio/ButtonStartChat/styles.module.scss @@ -0,0 +1,27 @@ +.button { + display: flex; + align-items: center; + justify-content: center; + padding: 10px 15px; + background: linear-gradient(360deg, #00789F 0%, #32009B 14.56%, #7500D2 44.15%, #DA00DE 84.23%, #FEDEC0 100%); + color: white; + border: none; + border-radius: 100px; + font-size: 14px; + font-weight: 600; + font-family: 'SF Pro Display', sans-serif; + text-transform: uppercase; + cursor: pointer; + transition: background 0.3s ease; + position: absolute; + top: 10px; + right: 10px; + + &:hover { + background: linear-gradient(360deg, #005F7F 0%, #26007B 14.56%, #5E00A8 44.15%, #AE00B2 84.23%, #CBB299 100%); + } + + svg { + margin-left: 8px; + } +} diff --git a/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonClsoe/index.tsx b/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonClsoe/index.tsx new file mode 100644 index 000000000..d2fffbace --- /dev/null +++ b/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonClsoe/index.tsx @@ -0,0 +1,28 @@ +import styles from './styles.module.scss'; + +export default function ButtonClose() { + return ( + + ); +} diff --git a/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonClsoe/styles.module.scss b/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonClsoe/styles.module.scss new file mode 100644 index 000000000..b3b362477 --- /dev/null +++ b/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonClsoe/styles.module.scss @@ -0,0 +1,5 @@ +.buttonClose { + display: flex; + align-items: center; + gap: 8px; +} \ No newline at end of file diff --git a/src/modules/blockchains/Buy/studio/Chatbox/index.tsx b/src/modules/blockchains/Buy/studio/Chatbox/index.tsx new file mode 100644 index 000000000..42abfd86c --- /dev/null +++ b/src/modules/blockchains/Buy/studio/Chatbox/index.tsx @@ -0,0 +1,185 @@ +import MagicIcon from '@/components/MagicIcon'; +import { useCallback, useEffect, useState } from 'react'; +import ButtonClose from './Actions/ButtonClsoe'; +import styles from './styles.module.scss'; + +export default function Chatbox() { + const [messages, setMessages] = useState< + Array<{ text: string; sender: string }> + >([]); + const [inputMessage, setInputMessage] = useState(''); + const [isListening, setIsListening] = useState(false); + + const [recognition, setRecognition] = useState( + null, + ); + + const handleSendMessage = () => { + if (inputMessage.trim() !== '') { + setMessages([...messages, { text: inputMessage, sender: 'user' }]); + setInputMessage(''); + } + }; + + useEffect(() => { + // Simulate response from the chatbot + if ( + messages.length > 0 && + messages[messages.length - 1].sender === 'user' + ) { + setTimeout(() => { + setMessages([ + ...messages, + { text: 'Hello! How can I help you?', sender: 'bot' }, + ]); + }, 1000); + } + }, [messages]); + + const stopVoiceInput = useCallback(() => { + if (recognition) { + recognition.stop(); + setIsListening(false); + setRecognition(null); + } + }, [recognition]); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + stopVoiceInput(); + } else if (event.ctrlKey && event.shiftKey && event.key === 'V') { + handleVoiceInput(); + } + }; + + window.addEventListener('keydown', handleKeyDown); + + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; + }, [stopVoiceInput]); + + const handleVoiceInput = () => { + setIsListening(true); + setInputMessage(''); // Clear input when starting voice input + const SpeechRecognition = + (window as any).SpeechRecognition || + (window as any).webkitSpeechRecognition; + const newRecognition = new SpeechRecognition(); + + // Remove the language setting to allow auto-detection + newRecognition.continuous = false; + newRecognition.interimResults = false; + + newRecognition.onresult = (event: any) => { + console.log('event.results', event.results); + const transcript = event.results[0][0].transcript; + setInputMessage(transcript); + setIsListening(false); + setRecognition(null); + }; + + // newRecognition.onaudioend = async (event: any) => { + // // console.log('onaudioend', event); + // console.log('newRecognition.audioBlob', newRecognition.audioBlob); + // if (newRecognition.audioBlob) { + // try { + // const formData = new FormData(); + // formData.append('audio', newRecognition.audioBlob, 'audio.wav'); + + // console.log('formData', newRecognition.audioBlob); + // const response = await fetch('/api/voice-to-text', { + // method: 'POST', + // body: formData, + // }); + // if (!response.ok) { + // throw new Error('Failed to send audio to API'); + // } + // const data = await response.json(); + // setInputMessage(data.transcript); + // } catch (error) { + // console.error('Error sending audio to API:', error); + // } + // } + // }; + + newRecognition.onerror = (event: any) => { + console.error('Speech recognition error:', event.error); + setIsListening(false); + setRecognition(null); + }; + + newRecognition.start(); + setRecognition(newRecognition); + }; + + return ( +
+
+
+
+
+ + Composer +
+
+
+ {messages.map((message, index) => ( +
+ {message.text} +
+ ))} +
+
+
Esc to close
+
+ {isListening && ( + + )} + + +
+
+
+
+
+