sksameermujahid's picture
Upload index.html
fd4e84f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HIVE PROP</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style>
/* Root Variables */
:root {
--primary-color: #31511E;
--secondary-color: #F6FCDF;
--accent-color: #859F3D;
--text-primary: rgb(26, 26, 25);
--text-secondary: rgb(49, 81, 30);
--border-radius: 20px;
--box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--transition: all 0.3s ease;
--chat-bg: #F6FCDF;
--bubble-user: #ffffff;
--bubble-bot: #31511E;
}
/* Property Search Styles */
body {
font-family: 'Poppins', sans-serif;
background-color: #F6FCDF;
margin: 0;
padding: 20px;
color: var(--text-primary);
}
h1 {
text-align: center;
color: var(--primary-color);
margin-bottom: 40px;
font-size: 3rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
position: relative;
animation: fadeIn 1s ease-in-out;
}
h1::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 100px;
height: 4px;
background: var(--primary-color);
border-radius: 2px;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Property Search Components */
.search-container {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 40px;
}
#queryForm {
display: flex;
gap: 20px;
align-items: center;
}
#userQuery {
width: 400px;
padding: 15px 25px;
border: 2px solid #E1E8ED;
border-radius: var(--border-radius);
font-size: 1.1rem;
transition: var(--transition);
background: white;
box-shadow: var(--box-shadow);
}
/* Property Card Styles */
.property {
display: flex;
flex-direction: row;
background: white;
border-radius: 30px;
box-shadow: var(--box-shadow);
margin-bottom: 30px;
overflow: hidden;
width: 90%;
margin-left: auto;
margin-right: auto;
transition: var(--transition);
gap: 20px;
padding: 20px;
animation: slideUp 0.5s ease-out;
position: relative;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.image-container {
flex: 2;
position: relative;
overflow: hidden;
border-radius: 20px;
box-shadow: var(--box-shadow);
}
.carousel {
width: 100%;
height: 100%;
}
.carousel-images {
display: flex;
transition: transform 0.5s ease-in-out;
height: 100%;
}
.carousel-image {
width: 100%;
height: 100%;
object-fit: cover;
flex-shrink: 0;
border-radius: 20px;
}
.property-details {
flex: 3;
display: flex;
flex-direction: column;
}
/* Accordion Styles */
.accordion-section {
border-bottom: 1px solid #E1E8ED;
}
.accordion-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 15px 0;
cursor: pointer;
border-bottom: 1px solid #E1E8ED;
transition: var(--transition);
}
.accordion-header:hover {
background-color: var(--secondary-color);
border-radius: 10px;
}
.accordion-content {
display: none;
padding: 15px 0;
color: var(--text-secondary);
line-height: 1.6;
}
/* Add active class for accordion */
.accordion-header.active + .accordion-content {
display: block; /* Show content when active */
}
/* Loading Spinner */
.loading-spinner {
border: 4px solid rgba(74, 144, 226, 0.1);
border-left-color: var(--primary-color);
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 40px auto;
}
.loading-message {
width: 40px;
height: 40px;
margin: auto auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error-message {
color: #DC3545;
text-align: center;
font-weight: 500;
margin-top: 20px;
}
@media (max-width: 1024px) {
.property {
flex-direction: column;
width: 95%;
}
.image-container {
width: 100%;
height: 300px;
}
#userQuery {
width: 300px;
}
}
@media (max-width: 768px) {
.search-container {
flex-direction: column;
align-items: center;
}
#queryForm {
flex-direction: column;
width: 100%;
max-width: 400px;
}
#userQuery {
width: 100%;
}
button {
width: 100%;
}
}
#userQuery:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.2);
}
#userQuery::placeholder {
color: #A4A4A4;
font-weight: 300;
}
.property:hover {
transform: translateY(-5px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
}
.carousel-nav {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
}
.carousel-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
cursor: pointer;
transition: var(--transition);
}
.carousel-dot.active {
background: white;
}
.property-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.property-header h2 {
font-size: 1.8rem;
font-weight: 700;
color: var(--text-primary);
margin: 0 0 10px 0;
}
.property-type {
display: inline-block;
padding: 8px 16px;
background-color: var(--accent-color);
color: white;
border-radius: 20px;
font-size: 0.9rem;
font-weight: 500;
}
.property-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 20px;
padding: 20px 0;
border-top: 1px solid #E1E8ED;
border-bottom: 1px solid #E1E8ED;
max-height: 300px; /* Set a max height for scrolling */
overflow-y: auto; /* Enable vertical scrolling */
scrollbar-width: thin; /* For Firefox */
scrollbar-color: var(--primary-color) var(--secondary-color); /* For Firefox */
}
.property-info::-webkit-scrollbar {
width: 8px; /* Width of the scrollbar */
}
.property-info::-webkit-scrollbar-track {
background: var(--secondary-color); /* Color of the scrollbar track */
border-radius: 10px;
}
.property-info::-webkit-scrollbar-thumb {
background: var(--primary-color); /* Color of the scrollbar thumb */
border-radius: 10px;
}
.property-info::-webkit-scrollbar-thumb:hover {
background: var(--accent-color); /* Color of the scrollbar thumb on hover */
}
.description {
margin: 10px 0;
line-height: 1.6;
color: var(--text-secondary);
}
.key-features {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin: 10px 0;
align-items: center;
}
.feature-pill {
background-color: var(--secondary-color);
padding: 2px 10px;
border-radius: 10px;
font-size: 0.9rem;
color: var(--text-primary);
font-weight: 500;
transition: var(--transition);
border: 2px solid var(--primary-color); /* Added border */
}
.feature-pill:hover {
background-color: var(--primary-color);
color: white;
transform: translateY(-2px);
}
.amenities-card {
background-color: var(--secondary-color);
border-radius: var(--border-radius);
padding: 20px;
margin: 10px 0;
}
.amenities-pills {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 10px;
}
.amenity-pill {
background-color: var(--secondary-color);
padding: 2px 10px;
border-radius: 10px;
font-size: 0.9rem;
color: var(--text-primary);
font-weight: 500;
transition: var(--transition);
border: 2px solid var(--primary-color); /* Added border */
}
.amenity-pill:hover {
background-color: var(--primary-color);
color: white;
transform: translateY(-2px);
}
.construction-status {
display: flex;
justify-content: space-between;
padding-top: 20px;
color: var(--text-secondary);
}
.accordion {
background-color: var(--secondary-color);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
margin-bottom: 20px;
overflow: hidden;
}
.accordion-header:hover {
}
.accordion-header .arrow {
transition: transform 0.3s ease;
}
.accordion-header.active .arrow {
transform: rotate(90deg);
}
.accordion-header strong {
font-size: 1.1rem;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 10px;
}
.accordion-arrow {
transition: transform 0.3s ease;
font-size: 0.9rem;
color: var(--primary-color);
}
.accordion-arrow.active {
transform: rotate(180deg);
}
.accordion-section:last-child {
border-bottom: none;
}
.accordion-header.active + .accordion-content {
display: block; /* Show content when active */
}
.favorite-button {
position: absolute;
top: 10px;
right: 10px;
background: none;
border: none;
color: white;
cursor: pointer;
padding: 10px;
border-radius: 50px;
display: flex;
background-color: var(--primary-color);
}
.favorite-button.active {
color: var(--primary-color);
background-color: var(--accent-color);
border: 2px solid var(--primary-color);
}
/* Chat Assistant Styles */
.chatbot-container {
position: fixed;
bottom: 2rem;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
padding: 0 2rem;
z-index: 1000;
}
.chatbot-icon {
width: 3.5rem;
height: 3.5rem;
background: var(--primary-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.chatbot-icon:hover {
transform: scale(1.1);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
}
.chatbot-icon i {
color: white;
font-size: 1.5rem;
}
.chat-container {
position: fixed;
bottom: 6rem;
width: 450px;
height: 35rem;
background: var(--chat-bg);
border-radius: 1rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
display: none;
flex-direction: column;
overflow: hidden;
z-index: 999;
animation: slideUp 0.3s ease-out;
border: 1px solid var(--primary-color); /* Added border */
}
.chat-header {
background: var(--primary-color);
color: white;
padding: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
position: relative;
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
}
.chat-header img {
width: 2rem;
height: 2rem;
border-radius: 50%;
}
.chat-header .close-button {
position: absolute;
right: 1rem;
background: none;
border: none;
font-size: 1.5rem;
color: white;
cursor: pointer;
}
/* Custom Scrollbar for Chatbot */
.chat-body::-webkit-scrollbar {
width: 12px; /* Width of the scrollbar */
}
.chat-body::-webkit-scrollbar-track {
background: var(--secondary-color); /* Color of the scrollbar track */
border-radius: 20px; /* Rounded corners for the track */
border: 2px solid var(--primary-color); /* Border around the track */
}
.chat-body::-webkit-scrollbar-thumb {
background: var(--primary-color); /* Color of the scrollbar thumb */
border-radius: 50%; /* Rounded corners for the thumb */
border: 2px solid var(--secondary-color); /* Border around the thumb */
}
.chat-body::-webkit-scrollbar-thumb:hover {
background: var(--accent-color); /* Color of the scrollbar thumb on hover */
}
/* For Firefox */
.chat-body {
scrollbar-width: thin; /* Width of the scrollbar */
scrollbar-color: var(--primary-color) var(--secondary-color); /* Color of the scrollbar thumb and track */
flex: 1;
padding: 1rem;
overflow-y: auto;
background: var(--background-color); /* Color of the scrollbar thumb and track */
}
.message {
display: flex;
flex-direction: column;
margin-bottom: 1rem;
}
.message-content {
max-width: 80%;
padding: 0.75rem 1rem;
border-radius: 1rem;
position: relative;
animation: messageAppear 0.3s ease-out;
}
@keyframes messageAppear {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.user-message {
align-items: flex-end;
}
.bot-message {
align-items: flex-start;
}
.user-message .message-content {
background: var(--bubble-user);
color: var(--text-color);
border-bottom-right-radius: 0.25rem;
}
.bot-message .message-content {
background: var(--bubble-bot);
color: white;
border-bottom-left-radius: 0.25rem;
}
.typing-indicator {
display: none;
padding: 0.75rem 1rem;
background: var(--bubble-bot);
color: white;
border-radius: 1rem;
border-bottom-left-radius: 0.25rem;
margin-bottom: 1rem;
width: fit-content;
}
.typing-dot {
display: inline-block;
width: 0.5rem;
height: 0.5rem;
margin: 0 0.1rem;
background: white;
border-radius: 50%;
animation: typing 1.4s infinite ease-in-out;
}
.typing-dot:nth-child(1) { animation-delay: 200ms; }
.typing-dot:nth-child(2) { animation-delay: 300ms; }
.typing-dot:nth-child(3) { animation-delay: 400ms; }
@keyframes typing {
0%, 60%, 100% { transform: translateY(0); }
30% { transform: translateY(-6px); }
}
.chat-footer {
padding: 1rem;
background: var(--chat-bg);
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.input-group {
display: flex;
gap: 0.5rem;
align-items: center;
}
.chat-input {
flex: 1;
padding: 0.75rem 1rem;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 1.5rem;
outline: none;
font-size: 0.95rem;
transition: border-color 0.3s ease;
}
.chat-input:focus {
border-color: var(--primary-color);
}
.send-chatbutton {
background: var(--bubble-bot);
color: white;
border: 2px solid var(--primary-color); /* Added border */
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.3s ease;
border-radius: 20px;
}
.send-chatbutton:hover {
background: var(--accent-color);
}
.timestamp {
font-size: 0.75rem;
color: #64748b;
margin-top: 0.25rem;
}
.property-card {
background: #f8fafc;
border-radius: 0.5rem;
padding: 1rem;
margin: 0.5rem 0;
border-left: 4px solid var(--primary-color);
box-shadow: var(--box-shadow);
}
.property-name {
font-weight: bold;
color: var(--primary-color);
margin-bottom: 0.5rem;
}
button {
padding: 15px 30px;
background-color: var(--primary-color);
color: white;
border: none;
border-radius: var(--border-radius);
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
font-family: 'Poppins', sans-serif;
box-shadow: var(--box-shadow);
}
button:hover {
background-color: #859F3D;
transform: translateY(-2px);
box-shadow: var(--box-shadow);
}
.loading-spinner {
border: 4px solid rgba(74, 144, 226, 0.1);
border-left-color: var(--primary-color);
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 40px auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error-message {
color: #DC3545;
text-align: center;
font-weight: 500;
margin-top: 20px;
}
@media (max-width: 1024px) {
.property {
flex-direction: column;
width: 95%;
}
.image-container {
width: 100%;
height: 300px;
}
#userQuery {
width: 300px;
}
}
@media (max-width: 768px) {
.search-container {
flex-direction: column;
align-items: center;
}
#queryForm {
flex-direction: column;
width: 100%;
max-width: 400px;
}
#userQuery {
width: 100%;
}
button {
width: 100%;
}
}
#userQuery:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.2);
}
#userQuery::placeholder {
color: #A4A4A4;
font-weight: 300;
}
.property:hover {
transform: translateY(-5px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
}
.carousel-nav {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
}
.carousel-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
cursor: pointer;
transition: var(--transition);
}
.carousel-dot.active {
background: white;
}
.property-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.property-header h2 {
font-size: 1.8rem;
font-weight: 700;
color: var(--text-primary);
margin: 0 0 10px 0;
}
.property-type {
display: inline-block;
padding: 8px 16px;
background-color: var(--accent-color);
color: white;
border-radius: 20px;
font-size: 0.9rem;
font-weight: 500;
}
.property-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 20px;
padding: 20px 0;
border-top: 1px solid #E1E8ED;
border-bottom: 1px solid #E1E8ED;
max-height: 300px; /* Set a max height for scrolling */
overflow-y: auto; /* Enable vertical scrolling */
scrollbar-width: thin; /* For Firefox */
scrollbar-color: var(--primary-color) var(--secondary-color); /* For Firefox */
}
.property-info::-webkit-scrollbar {
width: 8px; /* Width of the scrollbar */
}
.property-info::-webkit-scrollbar-track {
background: var(--secondary-color); /* Color of the scrollbar track */
border-radius: 10px;
}
.property-info::-webkit-scrollbar-thumb {
background: var(--primary-color); /* Color of the scrollbar thumb */
border-radius: 10px;
}
.property-info::-webkit-scrollbar-thumb:hover {
background: var(--accent-color); /* Color of the scrollbar thumb on hover */
}
.description {
margin: 10px 0;
line-height: 1.6;
color: var(--text-secondary);
}
.key-features {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin: 10px 0;
align-items: center;
}
.feature-pill {
background-color: var(--secondary-color);
padding: 2px 10px;
border-radius: 10px;
font-size: 0.9rem;
color: var(--text-primary);
font-weight: 500;
transition: var(--transition);
border: 2px solid var(--primary-color); /* Added border */
}
.feature-pill:hover {
background-color: var(--primary-color);
color: white;
transform: translateY(-2px);
}
.amenities-card {
background-color: var(--secondary-color);
border-radius: var(--border-radius);
padding: 20px;
margin: 10px 0;
}
.amenities-pills {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 10px;
}
.amenity-pill {
background-color: var(--secondary-color);
padding: 2px 10px;
border-radius: 10px;
font-size: 0.9rem;
color: var(--text-primary);
font-weight: 500;
transition: var(--transition);
border: 2px solid var(--primary-color); /* Added border */
}
.amenity-pill:hover {
background-color: var(--primary-color);
color: white;
transform: translateY(-2px);
}
.construction-status {
display: flex;
justify-content: space-between;
padding-top: 20px;
color: var(--text-secondary);
}
.accordion {
background-color: var(--secondary-color);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
margin-bottom: 20px;
overflow: hidden;
}
.accordion-header:hover {
}
.accordion-header .arrow {
transition: transform 0.3s ease;
}
.accordion-header.active .arrow {
transform: rotate(90deg);
}
.accordion-header strong {
font-size: 1.1rem;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 10px;
}
.accordion-arrow {
transition: transform 0.3s ease;
font-size: 0.9rem;
color: var(--primary-color);
}
.accordion-arrow.active {
transform: rotate(180deg);
}
.accordion-section:last-child {
border-bottom: none;
}
.accordion-header.active + .accordion-content {
display: block; /* Show content when active */
}
.quick-keywords::-webkit-scrollbar {
display: none;
}
.quick-keyword {
flex: 0 0 auto; /* Prevent buttons from shrinking */
padding: 10px 15px;
border-radius: 50px;
border: none;
color: white;
cursor: pointer;
white-space: nowrap;
}
</style>
</head>
<body>
<h1>HIVE PROP</h1>
<!-- Property Search Section -->
<div class="search-container">
<form id="queryForm">
<input type="text" id="userQuery" placeholder="Search for your dream property..." required>
<button type="button" id="microphoneButton">
<i class="fas fa-microphone"></i>
</button>
<button type="submit">Search Properties</button>
</form>
</div>
<div id="results"></div>
<div id="errorMessage" class="error-message"></div>
<div id="loadingMessage" style="display: none;">
<div class="loading-spinner"></div>
<!--<div class="loading-message">Loading...</div>-->
</div>
<div id="listeningMessage" style="display: none;">
<div class="loading-spinner"></div>
<div class="loading-message">Listening...</div>
</div>
<!-- Chat Assistant and Recommendations Container -->
<div class="chatbot-container">
<!-- Chat Assistant Icon -->
<div class="chatbot-icon" id="chatbot-icon" style="background-color: #31511E;">
<i class="fas fa-comment"></i>
</div>
<!-- Recommendations Icon -->
<div class="chatbot-icon" id="recommend-icon" style="background-color: #859F3D;">
<i class="fas fa-search"></i>
</div>
</div>
<!-- Chat Assistant Container -->
<div class="chat-container" id="chat-container" style="left: 2rem;">
<div class="chat-header">
<img src="/api/placeholder/32/32" alt="Bot Avatar">
<span>Hive Prop Chat Bot</span>
<button class="close-button">
<i class="fas fa-times"></i>
</button>
</div>
<div class="chat-body" id="chat-body">
<div class="message bot-message">
<div class="message-content">
Hello! I'm your real estate recommendation assistant. How can I help you today? Please reply with 'hi' to access your location.
</div>
<div class="timestamp">Now</div>
</div>
<div class="typing-indicator" id="typing-indicator">
<div class="typing-dot"></div>
<div class="typing-dot"></div>
<div class="typing-dot"></div>
</div>
</div>
<div class="chat-footer">
<div class="input-group">
<input type="text" class="chat-input" id="user-input" placeholder="Type your message..." required>
<button class="send-chatbutton" id="send-button">
<i class="fas fa-paper-plane"></i>
</button>
<button type="button" style="padding: 10px 15px;border-radius: 100px;" id="chatMicrophoneButton">
<i class="fas fa-microphone"></i>
</button>
</div>
<div class="quick-keywords">
<button class="quick-keyword" data-message="Show me nearby properties">Nearby Properties</button>
<button class="quick-keyword" data-message="Find luxury homes">Luxury Homes</button>
<button class="quick-keyword" data-message="Affordable apartments">Affordable Apartments</button>
<button class="quick-keyword" data-message="Properties with pools">Properties with Pools</button>
</div>
</div>
</div>
<!-- Recommendations Container -->
<div class="chat-container" id="recommend-container" style="right: 2rem;">
<div class="chat-header">
<img src="/content/sample_data/hive_prop.jpg" alt="Bot Avatar">
<span>Hive Prop Chatbot</span>
<button class="close-button">
<i class="fas fa-times"></i>
</button>
</div>
<div class="chat-body" id="recommend-body">
<div class="message bot-message">
<div class="message-content">
Hello! I'm your real estate recommendation assistant. How can I help you today? Please reply with 'hi' to access your location.
</div>
<div class="timestamp">Now</div>
</div>
<div class="typing-indicator" id="recommend-typing-indicator">
<div class="typing-dot"></div>
<div class="typing-dot"></div>
<div class="typing-dot"></div>
</div>
</div>
<div class="chat-footer">
<div class="input-group">
<input type="text" class="chat-input" id="recommend-input" placeholder="Type your message..." required>
<button class="send-chatbutton" id="recommend-send-button">
<i class="fas fa-paper-plane"></i>
</button>
<button type="button" style="padding: 10px 15px;border-radius: 100px;" id="recommendMicrophoneButton">
<i class="fas fa-microphone"></i>
</button>
</div>
<div class="quick-keywords" style="
border-radius:50px;
display: flex;
flex-direction: row;
overflow-x: auto;
white-space: nowrap;
gap: 10px;
padding: 10px;
scrollbar-width: none; /* Hide scrollbar for Firefox */
-ms-overflow-style: none; /* Hide scrollbar for IE/Edge */
position: relative;
background: white;
box-shadow: inset 20px 0 20px -10px rgba(0, 0, 0, 0.5), inset -20px 0 20px -10px rgba(0, 0, 0, 0.5);
">
<button class="quick-keyword" data-message="Show me nearby properties">Nearby Properties</button>
<button class="quick-keyword" data-message="Find luxury homes">Luxury Homes</button>
<button class="quick-keyword" data-message="Affordable apartments">Affordable Apartments</button>
<button class="quick-keyword" data-message="Properties with pools">Properties with Pools</button>
<button class="quick-keyword" data-message="Pet-friendly rentals">Pet-friendly Rentals</button>
<button class="quick-keyword" data-message="Beachfront properties">Beachfront Properties</button>
</div>
</div>
</div>
<script>
// Property Search Scripts
$(document).ready(function() {
$('#queryForm').on('submit', function(event) {
event.preventDefault();
const query = $('#userQuery').val();
$('#results').empty();
$('#errorMessage').empty();
$('#loadingMessage').show();
$.ajax({
url: '/search',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ query: query }),
success: function(data) {
$('#loadingMessage').hide();
if (data.error) {
$('#errorMessage').text('Error: ' + data.error);
} else {
data.forEach(function(property) {
const propertyElement = $(`
<div class="property">
<div class="image-container">
<div class="carousel">
<div class="carousel">
<div class="carousel-images">
<img src="${property['Property Image']}" alt="${property['Property Name']}" class="carousel-image">
</div>
</div>
</div>
<button class="favorite-button">
<i class="fas fa-heart"></i>
</button>
</div>
<div class="property-details">
<div class="property-header">
<h2>${property["Property Name"]}</h2>
<span class="property-type">${property["PropertyType"]}</span>
</div>
<div>
<span>
<strong>Location</strong>
${property["Address"]}, ${property["City"]}, ${property["State"]}, ${property["Country"]}
</span>
<span>
<strong>Zip Code</strong>
${property["ZipCode"]}
</span>
</div>
<div class="property-info">
<div class="scrollable-info" style="
display: flex;
justify-content: space-between"> <span>
<strong>Market Value</strong><br>
${property["MarketValue"]}
</span>
<span>
<strong>Total Square Feet</strong><br>
${property["TotalSquareFeet"]} sq ft
</span>
<span>
<strong>Bedrooms</strong><br>
${property["Beds"]}
</span>
<span>
<strong>Bathrooms</strong><br>
${property["Baths"]}
</span>
<span>
<strong>Contact</strong><br>
${property["Contact"]}
</span>
</div>
</div>
<div class="accordion-section">
<div class="accordion-header">
<strong>Description</strong>
<i class="fas fa-chevron-down accordion-arrow"></i>
</div>
<div class="accordion-content">
<p>${property["Description"]}</p>
</div>
</div>
<div class="accordion-section">
<div class="accordion-header">
<strong>Key Features</strong>
<i class="fas fa-chevron-down accordion-arrow"></i>
</div>
<div class="accordion-content">
<div class="key-features">
${property["KeyFeatures"].split(', ').map(feature => `
<span class="feature-pill">${feature}</span>
`).join('')}
</div>
</div>
</div>
<div class="accordion-section">
<div class="accordion-header">
<strong>Nearby Amenities</strong>
<i class="fas fa-chevron-down accordion-arrow"></i>
</div>
<div class="accordion-content">
<div class="amenities-pills">
${property["NearbyAmenities"].split(', ').map(amenity => `
<span class="amenity-pill">${amenity}</span>
`).join('')}
</div>
</div>
</div>
<div class="construction-status">
<p><strong>Property Status:</strong> ${property["PropertyStatus"]}</p>
<p><strong>Year Built:</strong> ${property["YearBuilt"]}</p>
</div>
<div class="accordion-section">
<div class="accordion-header">
<strong>Agent Details</strong>
<i class="fas fa-chevron-down accordion-arrow"></i>
</div>
<div class="accordion-content">
<div
style="display: flex; justify-content: space-between"> <span>
<strong>Agent Name</strong><br>
${property["AgentName"]}
</span>
<span>
<strong>Agent Phone Number</strong><br>
${property["AgentPhoneNumber"]}
</span>
<span>
<strong>Agent Email</strong><br>
${property["AgentEmail"]}
</span>
</div>
</div>
</div>
</div>
</div>
`);
$('#results').append(propertyElement);
propertyElement.find('.accordion-header').each(function() {
$(this).on('click', function() {
const $header = $(this);
const $content = $header.next('.accordion-content');
const $arrow = $header.find('.accordion-arrow');
$content.slideToggle(300);
$arrow.toggleClass('active');
const $otherHeaders = $header.closest('.property-details')
.find('.accordion-header').not($header);
$otherHeaders.each(function() {
$(this).next('.accordion-content').slideUp(300);
$(this).find('.accordion-arrow').removeClass('active');
});
});
});
propertyElement.find('.favorite-button').on('click', function() {
$(this).toggleClass('active');
});
});
}
},
error: function() {
$('#loadingMessage').hide();
$('#errorMessage').text('Error: Unable to fetch data. Please try again later.');
}
});
});
$('#queryForm').on('submit', function() {
$('html, body').animate({
scrollTop: $('#results').offset().top - 20
}, 1000);
});
$('#userQuery').on('focus', function() {
$(this).parent().addClass('focused');
}).on('blur', function() {
$(this).parent().removeClass('focused');
});
$(window).on('resize', function() {
if ($(window).width() <= 768) {
$('.property').addClass('mobile-view');
} else {
$('.property').removeClass('mobile-view');
}
});
$('[data-tooltip]').each(function() {
$(this).tooltip({
placement: 'top',
title: $(this).data('tooltip')
});
});
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
}
const microphoneButton = document.getElementById("microphoneButton");
const recognizer = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
recognizer.lang = 'en-US';
recognizer.continuous = true;
recognizer.interimResults = true;
let silenceTimer = null;
const SILENCE_DURATION = 3000;
microphoneButton.addEventListener("click", () => {
microphoneButton.classList.add('listening');
$('#listeningMessage').show();
recognizer.start();
console.log("Listening...");
});
recognizer.onresult = function(event) {
clearTimeout(silenceTimer);
let finalTranscript = '';
for (let i = event.resultIndex; i < event.results.length; i++) {
if (event.results[i].isFinal) {
finalTranscript += event.results[i][0].transcript;
}
}
if (finalTranscript) {
$('#userQuery').val(finalTranscript);
console.log("Transcript: ", finalTranscript);
}
silenceTimer = setTimeout(() => {
recognizer.stop();
console.log("Stopped listening due to silence");
}, SILENCE_DURATION);
};
recognizer.onend = function() {
console.log("Speech recognition service disconnected");
$('#listeningMessage').hide();
microphoneButton.classList.remove('listening');
clearTimeout(silenceTimer);
if ($('#userQuery').val().trim()) {
$('#queryForm').submit();
}
};
recognizer.onerror = function(event) {
console.error("Speech recognition error", event.error);
$('#listeningMessage').hide();
microphoneButton.classList.remove('listening');
clearTimeout(silenceTimer);
};
document.getElementById("chatbot-icon").addEventListener("click", function() {
const chatContainer = document.getElementById("chat-container");
chatContainer.style.display = chatContainer.style.display === "none" || chatContainer.style.display === "" ? "flex" : "none";
});
const chatBody = document.getElementById("chat-body");
const userInput = document.getElementById("user-input");
const sendButton = document.getElementById("send-button");
const typingIndicator = document.getElementById("typing-indicator");
function addMessage(content, isUser = false) {
const messageDiv = document.createElement("div");
messageDiv.className = `message ${isUser ? "user-message" : "bot-message"}`;
const messageContent = document.createElement("div");
messageContent.className = "message-content";
messageContent.innerHTML = formatMessageContent(content);
const timestamp = document.createElement("div");
timestamp.className = "timestamp";
timestamp.textContent = new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
messageDiv.appendChild(messageContent);
messageDiv.appendChild(timestamp);
chatBody.insertBefore(messageDiv, typingIndicator);
chatBody.scrollTop = chatBody.scrollHeight;
}
function handleUserInput() {
const message = userInput.value.trim().toLowerCase();
if (!message) return;
addMessage(message, true);
userInput.value = "";
typingIndicator.style.display = "block";
if (message === 'hi') {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
console.log("User Location:", latitude, longitude);
fetch("/set-location", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ latitude: latitude, longitude: longitude, session_id: 'chat-session' })
})
.then(response => response.json())
.then(data => {
console.log("Location set:", data);
const city = data.city;
const state = data.state;
const country = data.country;
addMessage(`Location set successfully in ${city}, ${state}, ${country}. Would you like to see nearby properties? Please reply with 'yes' or 'no'.`);
typingIndicator.style.display = "none";
})
.catch(error => {
console.error("Error setting location:", error);
addMessage("Unable to access your location. Please try again.");
typingIndicator.style.display = "none";
});
}, function(error) {
console.error("Error getting user location:", error);
addMessage("Unable to access your location. Please try again.");
typingIndicator.style.display = "none";
});
} else {
console.error("Geolocation is not supported by this browser.");
addMessage("Geolocation is not supported by your browser.");
typingIndicator.style.display = "none";
}
} else if (message === 'yes') {
fetch("/recommend", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ query: message, session_id: 'chat-session' })
})
.then(response => response.json())
.then(data => {
if (data.properties) {
let propertiesMessage = "Here are the 5 nearest properties to your location:\n";
data.properties.forEach(property => {
propertiesMessage += `* **${property.PropertyName}** at ${property.Address}, ${property.City}\n`;
propertiesMessage += ` Type: ${property.PropertyType}\n`; // Added property type
propertiesMessage += ` (Distance: ${property.Distance} miles)\n\n`; // Added a break before the distance
});
addMessage(propertiesMessage);
} else {
addMessage(data.response);
}
typingIndicator.style.display = "none";
})
.catch(error => {
console.error("Error:", error);
addMessage("I apologize, but I encountered an error. Could you please try again?");
typingIndicator.style.display = "none";
});
} else {
fetch("/generate", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ query: message, session_id: 'chat-session' })
})
.then(response => response.json())
.then(data => {
addMessage(data.response);
typingIndicator.style.display = "none";
})
.catch(error => {
console.error("Error:", error);
addMessage("I apologize, but I encountered an error. Could you please try again?");
typingIndicator.style.display = "none";
});
}
}
sendButton.addEventListener("click", handleUserInput);
userInput.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
handleUserInput();
}
});
const chatMicrophoneButton = document.getElementById("chatMicrophoneButton");
const chatRecognizer = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
chatRecognizer.lang = 'en-US';
chatRecognizer.continuous = true;
chatRecognizer.interimResults = true;
let chatSilenceTimer = null;
chatMicrophoneButton.addEventListener("click", () => {
chatMicrophoneButton.classList.add('listening');
$('#listeningMessage').show();
chatRecognizer.start();
console.log("Chat listening...");
});
chatRecognizer.onresult = function(event) {
clearTimeout(chatSilenceTimer);
let finalTranscript = '';
for (let i = event.resultIndex; i < event.results.length; i++) {
if (event.results[i].isFinal) {
finalTranscript += event.results[i][0].transcript;
}
}
if (finalTranscript) {
userInput.value = finalTranscript;
console.log("Chat Transcript: ", finalTranscript);
}
chatSilenceTimer = setTimeout(() => {
chatRecognizer.stop();
console.log("Stopped chat listening due to silence");
}, SILENCE_DURATION);
};
chatRecognizer.onend = function() {
console.log("Chat speech recognition service disconnected");
$('#listeningMessage').hide();
chatMicrophoneButton.classList.remove('listening');
clearTimeout(chatSilenceTimer);
if (userInput.value.trim()) {
handleUserInput();
}
};
chatRecognizer.onerror = function(event) {
console.error("Chat speech recognition error", event.error);
$('#listeningMessage').hide();
chatMicrophoneButton.classList.remove('listening');
clearTimeout(chatSilenceTimer);
};
document.getElementById("recommend-icon").addEventListener("click", function() {
const recommendContainer = document.getElementById("recommend-container");
recommendContainer.style.display = recommendContainer.style.display === "none" || recommendContainer.style.display === "" ? "flex" : "none";
});
const recommendBody = document.getElementById("recommend-body");
const recommendInput = document.getElementById("recommend-input");
const recommendSendButton = document.getElementById("recommend-send-button");
const recommendTypingIndicator = document.getElementById("recommend-typing-indicator");
function addRecommendMessage(content, isUser = false) {
const messageDiv = document.createElement("div");
messageDiv.className = `message ${isUser ? "user-message" : "bot-message"}`;
const messageContent = document.createElement("div");
messageContent.className = "message-content";
messageContent.innerHTML = formatMessageContent(content);
const timestamp = document.createElement("div");
timestamp.className = "timestamp";
timestamp.textContent = new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
messageDiv.appendChild(messageContent);
messageDiv.appendChild(timestamp);
recommendBody.insertBefore(messageDiv, recommendTypingIndicator);
recommendBody.scrollTop = recommendBody.scrollHeight;
}
function handleRecommendInput() {
const message = recommendInput.value.trim().toLowerCase();
if (!message) return;
addRecommendMessage(message, true);
recommendInput.value = "";
recommendTypingIndicator.style.display = "block";
if (message === 'hi') {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
console.log("User Location:", latitude, longitude);
fetch("/set-location", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ latitude: latitude, longitude: longitude, session_id: 'recommend-session' })
})
.then(response => response.json())
.then(data => {
console.log("Location set:", data);
const city = data.city;
const state = data.state;
const country = data.country;
addRecommendMessage(`Location set successfully in ${city}, ${state}, ${country}. Would you like to see nearby properties? Please reply with 'yes' or 'no'.`);
recommendTypingIndicator.style.display = "none";
})
.catch(error => {
console.error("Error setting location:", error);
addRecommendMessage("Unable to access your location. Please try again.");
recommendTypingIndicator.style.display = "none";
});
}, function(error) {
console.error("Error getting user location:", error);
addRecommendMessage("Unable to access your location. Please try again.");
recommendTypingIndicator.style.display = "none";
});
} else {
console.error("Geolocation is not supported by this browser.");
addRecommendMessage("Geolocation is not supported by your browser.");
recommendTypingIndicator.style.display = "none";
}
} else if (message === 'yes') {
fetch("/recommend", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ query: message, session_id: 'recommend-session' })
})
.then(response => response.json())
.then(data => {
if (data.properties) {
let propertiesMessage = "Here are the 5 nearest properties to your location:\n";
data.properties.forEach(property => {
propertiesMessage += `**${property.PropertyName}** at ${property.Address}, ${property.City}\n`;
propertiesMessage += ` Type: ${property.PropertyType}\n`; // Added property type
propertiesMessage += ` (Distance: ${property.Distance} miles)\n\n`; // Added a break before the distance
});
addRecommendMessage(propertiesMessage);
} else {
addRecommendMessage(data.response);
}
recommendTypingIndicator.style.display = "none";
})
.catch(error => {
console.error("Error:", error);
addRecommendMessage("I apologize, but I encountered an error. Could you please try again?");
recommendTypingIndicator.style.display = "none";
});
} else {
fetch("/recommend", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ query: message, session_id: 'recommend-session' })
})
.then(response => response.json())
.then(data => {
addRecommendMessage(data.response);
recommendTypingIndicator.style.display = "none";
})
.catch(error => {
console.error("Error:", error);
addRecommendMessage("I apologize, but I encountered an error. Could you please try again?");
recommendTypingIndicator.style.display = "none";
});
}
}
recommendSendButton.addEventListener("click", handleRecommendInput);
recommendInput.addEventListener("keypress", function(event) {
if (event.key === "Enter") {
handleRecommendInput();
}
});
const recommendMicrophoneButton = document.getElementById("recommendMicrophoneButton");
const recommendRecognizer = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
recommendRecognizer.lang = 'en-US';
recommendRecognizer.continuous = true;
recommendRecognizer.interimResults = true;
let recommendSilenceTimer = null;
recommendMicrophoneButton.addEventListener("click", () => {
recommendMicrophoneButton.classList.add('listening');
$('#listeningMessage').show();
recommendRecognizer.start();
console.log("Recommend listening...");
});
recommendRecognizer.onresult = function(event) {
clearTimeout(recommendSilenceTimer);
let finalTranscript = '';
for (let i = event.resultIndex; i < event.results.length; i++) {
if (event.results[i].isFinal) {
finalTranscript += event.results[i][0].transcript;
}
}
if (finalTranscript) {
recommendInput.value = finalTranscript;
console.log("Recommend Transcript: ", finalTranscript);
}
recommendSilenceTimer = setTimeout(() => {
recommendRecognizer.stop();
console.log("Stopped recommend listening due to silence");
}, SILENCE_DURATION);
};
recommendRecognizer.onend = function() {
console.log("Recommend speech recognition service disconnected");
$('#listeningMessage').hide();
recommendMicrophoneButton.classList.remove('listening');
clearTimeout(recommendSilenceTimer);
if (recommendInput.value.trim()) {
handleRecommendInput();
}
};
recommendRecognizer.onerror = function(event) {
console.error("Recommend speech recognition error", event.error);
$('#listeningMessage').hide();
recommendMicrophoneButton.classList.remove('listening');
clearTimeout(recommendSilenceTimer);
};
function formatMessageContent(content) {
content = content.replace(/\n/g, '<br>');
content = content.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
return content;
}
document.querySelectorAll('.quick-keyword').forEach(button => {
button.addEventListener('click', function() {
const message = this.getAttribute('data-message');
if (this.closest('#chat-container')) {
userInput.value = message;
handleUserInput();
} else if (this.closest('#recommend-container')) {
recommendInput.value = message;
handleRecommendInput();
}
});
});
});
</script>
</body>
</html>