import React, { useState, useEffect } from 'react'; import styles from './ChatBot.module.css'; import Camera from './Camera'; import { useSearchParams, useNavigate } from 'react-router-dom'; const ChatBot = ({ existingConversation }) => { const [messages, setMessages] = useState([ { sender: 'bot', text: 'Hai! Saya Alle, asisten virtual Dermalounge Clinic. Ada yang bisa Alle bantu hari ini?', time: getTime(), quickReplies: ['Konsultasi Estetik', 'Konsultasi Kulit & Kelamin'], }, ]); const [searchParams, setSearchParams] = useSearchParams(); const navigate = useNavigate(); const isOpenCamera = searchParams.get('camera') === 'open'; const [input, setInput] = useState(''); const [isLoading, setIsLoading] = useState(''); const [isPoppedUp, setIsPoppedUp] = useState(''); const [name, setName] = useState(''); const [phoneNumber, setPhoneNumber] = useState(''); useEffect(() => { if (existingConversation && existingConversation.length > 0) { setMessages(existingConversation); } }, [existingConversation]); useEffect(() => { if (!sessionStorage.getItem('session')) { function generateUUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } const sessionId = generateUUID(); const dateNow = new Date().toISOString(); sessionStorage.setItem('session', JSON.stringify({ sessionId, lastSeen: dateNow })); } }, []); function base64ToFile(base64Data, filename) { const arr = base64Data.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, { type: mime }); } const askToBot = async ({ type = 'text', content, tryCount = 0 }) => { const session = JSON.parse(sessionStorage.getItem('session')); if (!session || !session.sessionId) return; let body; let headers; const isBase64Image = type === 'image' && typeof content === 'string' && content.startsWith('data:image/'); if (isBase64Image) { const file = base64ToFile(content, 'photo.jpg'); const formData = new FormData(); formData.append('sessionId', session.sessionId); formData.append('lastSeen', new Date().toISOString()); formData.append('name', session.name || ''); formData.append('phoneNumber', session.phoneNumber || ''); formData.append('type', type); formData.append('image', file); body = formData; headers = {}; } else { body = JSON.stringify({ sessionId: session.sessionId, lastSeen: new Date().toISOString(), name: session.name, phoneNumber: session.phoneNumber, pertanyaan: content, type: type, }); headers = { 'Content-Type': 'application/json' }; } try { const response = await fetch('https://bot.kediritechnopark.com/webhook/master-agent/ask', { method: 'POST', headers, body, }); const data = await response.json(); return data; } catch (error) { if (tryCount < 3) { return new Promise((resolve) => setTimeout(() => resolve(askToBot({ type, content, tryCount: tryCount + 1 })), 3000) ); } else { console.error('Bot unavailable:', error); return { jawaban: 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti' }; } } }; const handleUploadImage = async (img) => { const session = JSON.parse(sessionStorage.getItem('session')); if (!session?.name || !session?.phoneNumber) { setIsPoppedUp(img); // simpan gambar untuk dikirim setelah user isi data setSearchParams({}); return; } setSearchParams({}); const newMessages = [ ...messages, { sender: 'user', img: img, time: getTime() }, ]; setMessages(newMessages); setIsLoading('Menganalisa gambar anda...'); const data = await askToBot({ type: 'image', content: img }); const botAnswer = data.jawaban || 'Maaf, saya tidak bisa menganalisis gambar tersebut.'; setMessages((prev) => [ ...prev, { sender: 'bot', text: botAnswer, time: getTime() }, ]); setIsLoading(''); }; const sendMessage = async (textOverride = null, name, phoneNumber, tryCount = 0) => { const message = textOverride || input.trim(); if (message === '') return; const session = JSON.parse(sessionStorage.getItem('session')); if ((!session || !session.name || !session.phoneNumber) && messages.length > 2) { setIsPoppedUp(message); setInput(''); return; } const newMessages = [...messages, { sender: 'user', text: message, time: getTime() }]; setMessages(newMessages); setInput(''); setIsLoading('Mengetik...'); try { const data = await askToBot({ type: 'text', content: message, tryCount }); const botAnswer = data.jawaban || 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti'; setMessages(prev => [ ...prev, { sender: 'bot', text: botAnswer, time: getTime() }, ]); setIsLoading(''); } catch (error) { console.error('Error sending message:', error); if (tryCount >= 3) { setMessages(prev => [ ...prev, { sender: 'bot', text: 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti', time: getTime() }, ]); setIsLoading(''); } else { setTimeout(() => sendMessage(message, name, phoneNumber, tryCount + 1), 3000); } } }; function formatBoldText(text) { const parts = text.split(/(\*\*[^\*]+\*\*)/g); return parts.flatMap((part, index) => { const elements = []; if (part.startsWith('**') && part.endsWith('**')) { part = part.slice(2, -2); part.split('\n').forEach((line, i) => { if (i > 0) elements.push(
); elements.push({line}); }); } else { part.split('\n').forEach((line, i) => { if (i > 0) elements.push(
); elements.push({line}); }); } return elements; }); } return (
Bot Avatar DERMALOUNGE
{isLoading !== '' && (
{isLoading}
)} {messages.slice().reverse().map((msg, index) => (
{msg.sender !== 'bot' ? ( msg.text ? msg.text : ) : ( (() => { try { return formatBoldText(msg.text); } catch (e) { return msg.text; } })() )} {msg.quickReplies && (
{msg.quickReplies.map((reply, i) => (
sendMessage(reply)}> {reply}
))}
setSearchParams({ camera: 'open' })} style={{ color: 'white', backgroundColor: '#075e54', display: 'flex', alignItems: 'center' }} > Analisa Gambar
)}
{msg.time}
))}
setInput(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && sendMessage()} disabled={isLoading !== ''} />
{isPoppedUp !== '' && (
Untuk bisa membantu Anda lebih jauh, boleh saya tahu nama dan nomor telepon Anda? Informasi ini juga membantu tim admin kami jika perlu melakukan follow-up nantinya 😊
setName(e.target.value)} maxLength={40} />
+62 { const value = e.target.value; if (/^\d{0,11}$/.test(value)) { setPhoneNumber(value); } }} />
{ if (name.length > 2 && phoneNumber.length >= 10) { const sessionData = JSON.parse(sessionStorage.getItem('session')) || {}; sessionData.name = name; sessionData.phoneNumber = phoneNumber; sessionStorage.setItem('session', JSON.stringify(sessionData)); setIsPoppedUp(''); if (typeof isPoppedUp === 'string' && isPoppedUp.startsWith('data:image/')) { handleUploadImage(isPoppedUp); } else { sendMessage(isPoppedUp); } } }} > Lanjut
)} {isOpenCamera && ( setSearchParams({})} handleUploadImage={(e) => handleUploadImage(e)} /> )}
); }; function getTime() { const now = new Date(); return now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } export default ChatBot;