diff --git a/adventure-rental-app/package-lock.json b/adventure-rental-app/package-lock.json index a639fbe..36188da 100644 --- a/adventure-rental-app/package-lock.json +++ b/adventure-rental-app/package-lock.json @@ -11,6 +11,7 @@ "axios": "^1.11.0", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-icons": "^5.5.0", "react-router-dom": "^7.7.1" }, "devDependencies": { @@ -3580,6 +3581,15 @@ "react": "^19.1.1" } }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", diff --git a/adventure-rental-app/package.json b/adventure-rental-app/package.json index fd7a4d8..eae0c45 100644 --- a/adventure-rental-app/package.json +++ b/adventure-rental-app/package.json @@ -13,6 +13,7 @@ "axios": "^1.11.0", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-icons": "^5.5.0", "react-router-dom": "^7.7.1" }, "devDependencies": { diff --git a/adventure-rental-app/src/App.jsx b/adventure-rental-app/src/App.jsx index e817b11..f8f8fa8 100644 --- a/adventure-rental-app/src/App.jsx +++ b/adventure-rental-app/src/App.jsx @@ -1,9 +1,16 @@ -import AuthPage from './AuthPage' +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import AuthPage from './AuthPage'; +import ChatbotPage from './ChatbotPage'; function App() { return ( - - ) + + + } /> + } /> + + + ); } export default App diff --git a/adventure-rental-app/src/ChatbotPage.jsx b/adventure-rental-app/src/ChatbotPage.jsx new file mode 100644 index 0000000..316f7af --- /dev/null +++ b/adventure-rental-app/src/ChatbotPage.jsx @@ -0,0 +1,121 @@ +import React, { useState } from 'react'; +import { FiCamera, FiSend, FiUser } from 'react-icons/fi'; + +const ChatbotPage = () => { + const [messages, setMessages] = useState([ + { id: 1, text: 'Halo Kak! 👋 Selamat datang di Adventure Rental. Saya Maya, asisten virtual yang siap membantu Anda. Ada yang bisa saya bantu?', sender: 'bot', timestamp: '10:30' }, + ]); + const [inputMessage, setInputMessage] = useState(''); + const [isTyping, setIsTyping] = useState(false); + + const handleSendMessage = () => { + if (inputMessage.trim() === '') return; + + const newMessage = { + id: messages.length + 1, + text: inputMessage, + sender: 'user', + timestamp: new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false }), + }; + setMessages((prevMessages) => [...prevMessages, newMessage]); + setInputMessage(''); + setIsTyping(true); + + // Simulate bot response + setTimeout(() => { + const botResponse = { + id: messages.length + 3, // Adjusted for the new message and typing indicator + text: `Anda mengirim: "${inputMessage}"`, + sender: 'bot', + timestamp: new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false }), + }; + setIsTyping(false); + setMessages((prevMessages) => [...prevMessages, botResponse]); + }, 2000); + }; + + const handleKeyPress = (e) => { + if (e.key === 'Enter') { + handleSendMessage(); + } + }; + + return ( +
+
+ {/* Header */} +
+
+ M +
+
+

Maya

+

Adventure Assistant

+
+
+ + {/* Chat Window */} +
+ {messages.map((message) => ( +
+
+
+

{message.text}

+

{message.timestamp}

+
+
+ {message.sender === 'bot' && ( +
+ M +
+ )} + {message.sender === 'user' && ( +
+ +
+ )} +
+ ))} + {isTyping && ( +
+
+ M +
+
+
+
+ + + +
+
+
+
+ )} +
+ + {/* Input Area */} +
+
+ setInputMessage(e.target.value)} + onKeyPress={handleKeyPress} + /> +
+ +
+
+
+ ); +}; + +export default ChatbotPage; \ No newline at end of file diff --git a/adventure-rental-app/src/index.css b/adventure-rental-app/src/index.css index 58559a9..bd9ab4f 100644 --- a/adventure-rental-app/src/index.css +++ b/adventure-rental-app/src/index.css @@ -17,3 +17,35 @@ input:-webkit-autofill:active { transition: background-color 5000s ease-in-out 0s; } + +.typing-indicator { + display: flex; + align-items: center; +} + +.typing-indicator span { + height: 8px; + width: 8px; + background-color: #9E9E9E; + border-radius: 50%; + display: inline-block; + margin: 0 2px; + animation: typing-wave 1.4s infinite ease-in-out both; +} + +.typing-indicator span:nth-child(1) { + animation-delay: -0.32s; +} + +.typing-indicator span:nth-child(2) { + animation-delay: -0.16s; +} + +@keyframes typing-wave { + 0%, 80%, 100% { + transform: scale(0); + } + 40% { + transform: scale(1.0); + } +} diff --git a/adventure-rental-app/tailwind.config.js b/adventure-rental-app/tailwind.config.js index 83f7b3c..1368b89 100644 --- a/adventure-rental-app/tailwind.config.js +++ b/adventure-rental-app/tailwind.config.js @@ -12,6 +12,9 @@ export default { 'brand-light': '#F5F5DC', 'brand-gray': '#A9A9A9', 'brand-orange': '#D97706', // Adventure Orange + 'chat-header': '#003C5A', + 'chat-bg': '#0084A8', + 'chat-input-bg': '#0A192F', }, fontFamily: { sans: ['Poppins', 'sans-serif'],