sksameermujahid commited on
Commit
fd4e84f
·
verified ·
1 Parent(s): 35acb64

Upload index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +1838 -0
templates/index.html ADDED
@@ -0,0 +1,1838 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>HIVE PROP</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
8
+ <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
9
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
10
+ <style>
11
+ /* Root Variables */
12
+ :root {
13
+ --primary-color: #31511E;
14
+ --secondary-color: #F6FCDF;
15
+ --accent-color: #859F3D;
16
+ --text-primary: rgb(26, 26, 25);
17
+ --text-secondary: rgb(49, 81, 30);
18
+ --border-radius: 20px;
19
+ --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
20
+ --transition: all 0.3s ease;
21
+ --chat-bg: #F6FCDF;
22
+ --bubble-user: #ffffff;
23
+ --bubble-bot: #31511E;
24
+ }
25
+
26
+ /* Property Search Styles */
27
+ body {
28
+ font-family: 'Poppins', sans-serif;
29
+ background-color: #F6FCDF;
30
+ margin: 0;
31
+ padding: 20px;
32
+ color: var(--text-primary);
33
+ }
34
+
35
+ h1 {
36
+ text-align: center;
37
+ color: var(--primary-color);
38
+ margin-bottom: 40px;
39
+ font-size: 3rem;
40
+ font-weight: 700;
41
+ text-transform: uppercase;
42
+ letter-spacing: 2px;
43
+ position: relative;
44
+ animation: fadeIn 1s ease-in-out;
45
+ }
46
+
47
+ h1::after {
48
+ content: '';
49
+ position: absolute;
50
+ bottom: -10px;
51
+ left: 50%;
52
+ transform: translateX(-50%);
53
+ width: 100px;
54
+ height: 4px;
55
+ background: var(--primary-color);
56
+ border-radius: 2px;
57
+ }
58
+
59
+ @keyframes fadeIn {
60
+ from {
61
+ opacity: 0;
62
+ transform: translateY(-20px);
63
+ }
64
+ to {
65
+ opacity: 1;
66
+ transform: translateY(0);
67
+ }
68
+ }
69
+
70
+ /* Property Search Components */
71
+ .search-container {
72
+ display: flex;
73
+ justify-content: center;
74
+ gap: 20px;
75
+ margin-bottom: 40px;
76
+ }
77
+
78
+ #queryForm {
79
+ display: flex;
80
+ gap: 20px;
81
+ align-items: center;
82
+ }
83
+
84
+ #userQuery {
85
+ width: 400px;
86
+ padding: 15px 25px;
87
+ border: 2px solid #E1E8ED;
88
+ border-radius: var(--border-radius);
89
+ font-size: 1.1rem;
90
+ transition: var(--transition);
91
+ background: white;
92
+ box-shadow: var(--box-shadow);
93
+ }
94
+
95
+ /* Property Card Styles */
96
+ .property {
97
+ display: flex;
98
+ flex-direction: row;
99
+ background: white;
100
+ border-radius: 30px;
101
+ box-shadow: var(--box-shadow);
102
+ margin-bottom: 30px;
103
+ overflow: hidden;
104
+ width: 90%;
105
+ margin-left: auto;
106
+ margin-right: auto;
107
+ transition: var(--transition);
108
+ gap: 20px;
109
+ padding: 20px;
110
+ animation: slideUp 0.5s ease-out;
111
+ position: relative;
112
+ }
113
+
114
+ @keyframes slideUp {
115
+ from {
116
+ opacity: 0;
117
+ transform: translateY(20px);
118
+ }
119
+ to {
120
+ opacity: 1;
121
+ transform: translateY(0);
122
+ }
123
+ }
124
+
125
+ .image-container {
126
+ flex: 2;
127
+ position: relative;
128
+ overflow: hidden;
129
+ border-radius: 20px;
130
+ box-shadow: var(--box-shadow);
131
+ }
132
+
133
+ .carousel {
134
+ width: 100%;
135
+ height: 100%;
136
+ }
137
+
138
+ .carousel-images {
139
+ display: flex;
140
+ transition: transform 0.5s ease-in-out;
141
+ height: 100%;
142
+ }
143
+
144
+ .carousel-image {
145
+ width: 100%;
146
+ height: 100%;
147
+ object-fit: cover;
148
+ flex-shrink: 0;
149
+ border-radius: 20px;
150
+ }
151
+
152
+ .property-details {
153
+ flex: 3;
154
+ display: flex;
155
+ flex-direction: column;
156
+ }
157
+
158
+ /* Accordion Styles */
159
+ .accordion-section {
160
+ border-bottom: 1px solid #E1E8ED;
161
+ }
162
+
163
+ .accordion-header {
164
+ display: flex;
165
+ align-items: center;
166
+ justify-content: space-between;
167
+ padding: 15px 0;
168
+ cursor: pointer;
169
+ border-bottom: 1px solid #E1E8ED;
170
+ transition: var(--transition);
171
+ }
172
+
173
+ .accordion-header:hover {
174
+ background-color: var(--secondary-color);
175
+ border-radius: 10px;
176
+ }
177
+
178
+ .accordion-content {
179
+ display: none;
180
+ padding: 15px 0;
181
+ color: var(--text-secondary);
182
+ line-height: 1.6;
183
+ }
184
+
185
+ /* Add active class for accordion */
186
+ .accordion-header.active + .accordion-content {
187
+ display: block; /* Show content when active */
188
+ }
189
+
190
+ /* Loading Spinner */
191
+ .loading-spinner {
192
+ border: 4px solid rgba(74, 144, 226, 0.1);
193
+ border-left-color: var(--primary-color);
194
+ border-radius: 50%;
195
+ width: 40px;
196
+ height: 40px;
197
+ animation: spin 1s linear infinite;
198
+ margin: 40px auto;
199
+ }
200
+
201
+ .loading-message {
202
+ width: 40px;
203
+ height: 40px;
204
+ margin: auto auto;
205
+ }
206
+
207
+ @keyframes spin {
208
+ 0% { transform: rotate(0deg); }
209
+ 100% { transform: rotate(360deg); }
210
+ }
211
+
212
+ .error-message {
213
+ color: #DC3545;
214
+ text-align: center;
215
+ font-weight: 500;
216
+ margin-top: 20px;
217
+ }
218
+
219
+ @media (max-width: 1024px) {
220
+ .property {
221
+ flex-direction: column;
222
+ width: 95%;
223
+ }
224
+
225
+ .image-container {
226
+ width: 100%;
227
+ height: 300px;
228
+ }
229
+
230
+ #userQuery {
231
+ width: 300px;
232
+ }
233
+ }
234
+
235
+ @media (max-width: 768px) {
236
+ .search-container {
237
+ flex-direction: column;
238
+ align-items: center;
239
+ }
240
+
241
+ #queryForm {
242
+ flex-direction: column;
243
+ width: 100%;
244
+ max-width: 400px;
245
+ }
246
+
247
+ #userQuery {
248
+ width: 100%;
249
+ }
250
+
251
+ button {
252
+ width: 100%;
253
+ }
254
+ }
255
+
256
+ #userQuery:focus {
257
+ outline: none;
258
+ border-color: var(--primary-color);
259
+ box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.2);
260
+ }
261
+
262
+ #userQuery::placeholder {
263
+ color: #A4A4A4;
264
+ font-weight: 300;
265
+ }
266
+
267
+ .property:hover {
268
+ transform: translateY(-5px);
269
+ box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
270
+ }
271
+
272
+ .carousel-nav {
273
+ position: absolute;
274
+ bottom: 20px;
275
+ left: 50%;
276
+ transform: translateX(-50%);
277
+ display: flex;
278
+ gap: 10px;
279
+ }
280
+
281
+ .carousel-dot {
282
+ width: 10px;
283
+ height: 10px;
284
+ border-radius: 50%;
285
+ background: rgba(255, 255, 255, 0.5);
286
+ cursor: pointer;
287
+ transition: var(--transition);
288
+ }
289
+
290
+ .carousel-dot.active {
291
+ background: white;
292
+ }
293
+
294
+ .property-header {
295
+ display: flex;
296
+ justify-content: space-between;
297
+ align-items: center;
298
+ }
299
+
300
+ .property-header h2 {
301
+ font-size: 1.8rem;
302
+ font-weight: 700;
303
+ color: var(--text-primary);
304
+ margin: 0 0 10px 0;
305
+ }
306
+
307
+ .property-type {
308
+ display: inline-block;
309
+ padding: 8px 16px;
310
+ background-color: var(--accent-color);
311
+ color: white;
312
+ border-radius: 20px;
313
+ font-size: 0.9rem;
314
+ font-weight: 500;
315
+ }
316
+
317
+ .property-info {
318
+ display: grid;
319
+ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
320
+ gap: 20px;
321
+ padding: 20px 0;
322
+ border-top: 1px solid #E1E8ED;
323
+ border-bottom: 1px solid #E1E8ED;
324
+ max-height: 300px; /* Set a max height for scrolling */
325
+ overflow-y: auto; /* Enable vertical scrolling */
326
+ scrollbar-width: thin; /* For Firefox */
327
+ scrollbar-color: var(--primary-color) var(--secondary-color); /* For Firefox */
328
+ }
329
+
330
+ .property-info::-webkit-scrollbar {
331
+ width: 8px; /* Width of the scrollbar */
332
+ }
333
+
334
+ .property-info::-webkit-scrollbar-track {
335
+ background: var(--secondary-color); /* Color of the scrollbar track */
336
+ border-radius: 10px;
337
+ }
338
+
339
+ .property-info::-webkit-scrollbar-thumb {
340
+ background: var(--primary-color); /* Color of the scrollbar thumb */
341
+ border-radius: 10px;
342
+ }
343
+
344
+ .property-info::-webkit-scrollbar-thumb:hover {
345
+ background: var(--accent-color); /* Color of the scrollbar thumb on hover */
346
+ }
347
+
348
+ .description {
349
+ margin: 10px 0;
350
+ line-height: 1.6;
351
+ color: var(--text-secondary);
352
+ }
353
+
354
+ .key-features {
355
+ display: flex;
356
+ flex-wrap: wrap;
357
+ gap: 10px;
358
+ margin: 10px 0;
359
+ align-items: center;
360
+ }
361
+
362
+ .feature-pill {
363
+ background-color: var(--secondary-color);
364
+ padding: 2px 10px;
365
+ border-radius: 10px;
366
+ font-size: 0.9rem;
367
+ color: var(--text-primary);
368
+ font-weight: 500;
369
+ transition: var(--transition);
370
+ border: 2px solid var(--primary-color); /* Added border */
371
+ }
372
+
373
+ .feature-pill:hover {
374
+ background-color: var(--primary-color);
375
+ color: white;
376
+ transform: translateY(-2px);
377
+ }
378
+
379
+ .amenities-card {
380
+ background-color: var(--secondary-color);
381
+ border-radius: var(--border-radius);
382
+ padding: 20px;
383
+ margin: 10px 0;
384
+ }
385
+
386
+ .amenities-pills {
387
+ display: flex;
388
+ flex-wrap: wrap;
389
+ gap: 10px;
390
+ margin-top: 10px;
391
+ }
392
+
393
+ .amenity-pill {
394
+ background-color: var(--secondary-color);
395
+ padding: 2px 10px;
396
+ border-radius: 10px;
397
+ font-size: 0.9rem;
398
+ color: var(--text-primary);
399
+ font-weight: 500;
400
+ transition: var(--transition);
401
+ border: 2px solid var(--primary-color); /* Added border */
402
+ }
403
+
404
+ .amenity-pill:hover {
405
+ background-color: var(--primary-color);
406
+ color: white;
407
+ transform: translateY(-2px);
408
+ }
409
+
410
+ .construction-status {
411
+ display: flex;
412
+ justify-content: space-between;
413
+ padding-top: 20px;
414
+ color: var(--text-secondary);
415
+ }
416
+
417
+ .accordion {
418
+ background-color: var(--secondary-color);
419
+ border-radius: var(--border-radius);
420
+ box-shadow: var(--box-shadow);
421
+ margin-bottom: 20px;
422
+ overflow: hidden;
423
+ }
424
+
425
+ .accordion-header:hover {
426
+ }
427
+
428
+ .accordion-header .arrow {
429
+ transition: transform 0.3s ease;
430
+ }
431
+
432
+ .accordion-header.active .arrow {
433
+ transform: rotate(90deg);
434
+ }
435
+
436
+ .accordion-header strong {
437
+ font-size: 1.1rem;
438
+ color: var(--text-primary);
439
+ display: flex;
440
+ align-items: center;
441
+ gap: 10px;
442
+ }
443
+
444
+ .accordion-arrow {
445
+ transition: transform 0.3s ease;
446
+ font-size: 0.9rem;
447
+ color: var(--primary-color);
448
+ }
449
+
450
+ .accordion-arrow.active {
451
+ transform: rotate(180deg);
452
+ }
453
+
454
+ .accordion-section:last-child {
455
+ border-bottom: none;
456
+ }
457
+
458
+ .accordion-header.active + .accordion-content {
459
+ display: block; /* Show content when active */
460
+ }
461
+
462
+ .favorite-button {
463
+ position: absolute;
464
+ top: 10px;
465
+ right: 10px;
466
+ background: none;
467
+ border: none;
468
+ color: white;
469
+ cursor: pointer;
470
+ padding: 10px;
471
+ border-radius: 50px;
472
+ display: flex;
473
+ background-color: var(--primary-color);
474
+ }
475
+
476
+ .favorite-button.active {
477
+ color: var(--primary-color);
478
+ background-color: var(--accent-color);
479
+ border: 2px solid var(--primary-color);
480
+ }
481
+
482
+ /* Chat Assistant Styles */
483
+ .chatbot-container {
484
+ position: fixed;
485
+ bottom: 2rem;
486
+ left: 0;
487
+ right: 0;
488
+ display: flex;
489
+ justify-content: space-between;
490
+ padding: 0 2rem;
491
+ z-index: 1000;
492
+ }
493
+
494
+ .chatbot-icon {
495
+ width: 3.5rem;
496
+ height: 3.5rem;
497
+ background: var(--primary-color);
498
+ border-radius: 50%;
499
+ display: flex;
500
+ align-items: center;
501
+ justify-content: center;
502
+ cursor: pointer;
503
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
504
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
505
+ }
506
+
507
+ .chatbot-icon:hover {
508
+ transform: scale(1.1);
509
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
510
+ }
511
+
512
+ .chatbot-icon i {
513
+ color: white;
514
+ font-size: 1.5rem;
515
+ }
516
+
517
+ .chat-container {
518
+ position: fixed;
519
+ bottom: 6rem;
520
+ width: 450px;
521
+ height: 35rem;
522
+ background: var(--chat-bg);
523
+ border-radius: 1rem;
524
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
525
+ display: none;
526
+ flex-direction: column;
527
+ overflow: hidden;
528
+ z-index: 999;
529
+ animation: slideUp 0.3s ease-out;
530
+ border: 1px solid var(--primary-color); /* Added border */
531
+ }
532
+
533
+ .chat-header {
534
+ background: var(--primary-color);
535
+ color: white;
536
+ padding: 1rem;
537
+ display: flex;
538
+ align-items: center;
539
+ gap: 0.5rem;
540
+ position: relative;
541
+ border-top-left-radius: 1rem;
542
+ border-top-right-radius: 1rem;
543
+ }
544
+
545
+ .chat-header img {
546
+ width: 2rem;
547
+ height: 2rem;
548
+ border-radius: 50%;
549
+ }
550
+
551
+ .chat-header .close-button {
552
+ position: absolute;
553
+ right: 1rem;
554
+ background: none;
555
+ border: none;
556
+ font-size: 1.5rem;
557
+ color: white;
558
+ cursor: pointer;
559
+ }
560
+
561
+ /* Custom Scrollbar for Chatbot */
562
+ .chat-body::-webkit-scrollbar {
563
+ width: 12px; /* Width of the scrollbar */
564
+ }
565
+
566
+ .chat-body::-webkit-scrollbar-track {
567
+ background: var(--secondary-color); /* Color of the scrollbar track */
568
+ border-radius: 20px; /* Rounded corners for the track */
569
+ border: 2px solid var(--primary-color); /* Border around the track */
570
+ }
571
+
572
+ .chat-body::-webkit-scrollbar-thumb {
573
+ background: var(--primary-color); /* Color of the scrollbar thumb */
574
+ border-radius: 50%; /* Rounded corners for the thumb */
575
+ border: 2px solid var(--secondary-color); /* Border around the thumb */
576
+ }
577
+
578
+ .chat-body::-webkit-scrollbar-thumb:hover {
579
+ background: var(--accent-color); /* Color of the scrollbar thumb on hover */
580
+ }
581
+
582
+ /* For Firefox */
583
+ .chat-body {
584
+ scrollbar-width: thin; /* Width of the scrollbar */
585
+ scrollbar-color: var(--primary-color) var(--secondary-color); /* Color of the scrollbar thumb and track */
586
+ flex: 1;
587
+ padding: 1rem;
588
+ overflow-y: auto;
589
+ background: var(--background-color); /* Color of the scrollbar thumb and track */
590
+ }
591
+
592
+ .message {
593
+ display: flex;
594
+ flex-direction: column;
595
+ margin-bottom: 1rem;
596
+ }
597
+
598
+ .message-content {
599
+ max-width: 80%;
600
+ padding: 0.75rem 1rem;
601
+ border-radius: 1rem;
602
+ position: relative;
603
+ animation: messageAppear 0.3s ease-out;
604
+ }
605
+
606
+ @keyframes messageAppear {
607
+ from {
608
+ opacity: 0;
609
+ transform: translateY(10px);
610
+ }
611
+ to {
612
+ opacity: 1;
613
+ transform: translateY(0);
614
+ }
615
+ }
616
+
617
+ .user-message {
618
+ align-items: flex-end;
619
+ }
620
+
621
+ .bot-message {
622
+ align-items: flex-start;
623
+ }
624
+
625
+ .user-message .message-content {
626
+ background: var(--bubble-user);
627
+ color: var(--text-color);
628
+ border-bottom-right-radius: 0.25rem;
629
+ }
630
+
631
+ .bot-message .message-content {
632
+ background: var(--bubble-bot);
633
+ color: white;
634
+ border-bottom-left-radius: 0.25rem;
635
+ }
636
+
637
+ .typing-indicator {
638
+ display: none;
639
+ padding: 0.75rem 1rem;
640
+ background: var(--bubble-bot);
641
+ color: white;
642
+ border-radius: 1rem;
643
+ border-bottom-left-radius: 0.25rem;
644
+ margin-bottom: 1rem;
645
+ width: fit-content;
646
+ }
647
+
648
+ .typing-dot {
649
+ display: inline-block;
650
+ width: 0.5rem;
651
+ height: 0.5rem;
652
+ margin: 0 0.1rem;
653
+ background: white;
654
+ border-radius: 50%;
655
+ animation: typing 1.4s infinite ease-in-out;
656
+ }
657
+
658
+ .typing-dot:nth-child(1) { animation-delay: 200ms; }
659
+ .typing-dot:nth-child(2) { animation-delay: 300ms; }
660
+ .typing-dot:nth-child(3) { animation-delay: 400ms; }
661
+
662
+ @keyframes typing {
663
+ 0%, 60%, 100% { transform: translateY(0); }
664
+ 30% { transform: translateY(-6px); }
665
+ }
666
+
667
+ .chat-footer {
668
+ padding: 1rem;
669
+ background: var(--chat-bg);
670
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
671
+ }
672
+
673
+ .input-group {
674
+ display: flex;
675
+ gap: 0.5rem;
676
+ align-items: center;
677
+ }
678
+
679
+ .chat-input {
680
+ flex: 1;
681
+ padding: 0.75rem 1rem;
682
+ border: 1px solid rgba(0, 0, 0, 0.1);
683
+ border-radius: 1.5rem;
684
+ outline: none;
685
+ font-size: 0.95rem;
686
+ transition: border-color 0.3s ease;
687
+ }
688
+
689
+ .chat-input:focus {
690
+ border-color: var(--primary-color);
691
+ }
692
+
693
+ .send-chatbutton {
694
+ background: var(--bubble-bot);
695
+ color: white;
696
+ border: 2px solid var(--primary-color); /* Added border */
697
+ width: 2.5rem;
698
+ height: 2.5rem;
699
+ border-radius: 50%;
700
+ cursor: pointer;
701
+ display: flex;
702
+ align-items: center;
703
+ justify-content: center;
704
+ transition: background-color 0.3s ease;
705
+ border-radius: 20px;
706
+ }
707
+
708
+ .send-chatbutton:hover {
709
+ background: var(--accent-color);
710
+ }
711
+
712
+ .timestamp {
713
+ font-size: 0.75rem;
714
+ color: #64748b;
715
+ margin-top: 0.25rem;
716
+ }
717
+
718
+ .property-card {
719
+ background: #f8fafc;
720
+ border-radius: 0.5rem;
721
+ padding: 1rem;
722
+ margin: 0.5rem 0;
723
+ border-left: 4px solid var(--primary-color);
724
+ box-shadow: var(--box-shadow);
725
+ }
726
+
727
+ .property-name {
728
+ font-weight: bold;
729
+ color: var(--primary-color);
730
+ margin-bottom: 0.5rem;
731
+ }
732
+
733
+ button {
734
+ padding: 15px 30px;
735
+ background-color: var(--primary-color);
736
+ color: white;
737
+ border: none;
738
+ border-radius: var(--border-radius);
739
+ font-size: 1.1rem;
740
+ font-weight: 600;
741
+ cursor: pointer;
742
+ transition: var(--transition);
743
+ font-family: 'Poppins', sans-serif;
744
+ box-shadow: var(--box-shadow);
745
+ }
746
+
747
+ button:hover {
748
+ background-color: #859F3D;
749
+ transform: translateY(-2px);
750
+ box-shadow: var(--box-shadow);
751
+ }
752
+
753
+ .loading-spinner {
754
+ border: 4px solid rgba(74, 144, 226, 0.1);
755
+ border-left-color: var(--primary-color);
756
+ border-radius: 50%;
757
+ width: 40px;
758
+ height: 40px;
759
+ animation: spin 1s linear infinite;
760
+ margin: 40px auto;
761
+ }
762
+
763
+ @keyframes spin {
764
+ 0% { transform: rotate(0deg); }
765
+ 100% { transform: rotate(360deg); }
766
+ }
767
+
768
+ .error-message {
769
+ color: #DC3545;
770
+ text-align: center;
771
+ font-weight: 500;
772
+ margin-top: 20px;
773
+ }
774
+
775
+ @media (max-width: 1024px) {
776
+ .property {
777
+ flex-direction: column;
778
+ width: 95%;
779
+ }
780
+
781
+ .image-container {
782
+ width: 100%;
783
+ height: 300px;
784
+ }
785
+
786
+ #userQuery {
787
+ width: 300px;
788
+ }
789
+ }
790
+
791
+ @media (max-width: 768px) {
792
+ .search-container {
793
+ flex-direction: column;
794
+ align-items: center;
795
+ }
796
+
797
+ #queryForm {
798
+ flex-direction: column;
799
+ width: 100%;
800
+ max-width: 400px;
801
+ }
802
+
803
+ #userQuery {
804
+ width: 100%;
805
+ }
806
+
807
+ button {
808
+ width: 100%;
809
+ }
810
+ }
811
+
812
+ #userQuery:focus {
813
+ outline: none;
814
+ border-color: var(--primary-color);
815
+ box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.2);
816
+ }
817
+
818
+ #userQuery::placeholder {
819
+ color: #A4A4A4;
820
+ font-weight: 300;
821
+ }
822
+
823
+ .property:hover {
824
+ transform: translateY(-5px);
825
+ box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
826
+ }
827
+
828
+ .carousel-nav {
829
+ position: absolute;
830
+ bottom: 20px;
831
+ left: 50%;
832
+ transform: translateX(-50%);
833
+ display: flex;
834
+ gap: 10px;
835
+ }
836
+
837
+ .carousel-dot {
838
+ width: 10px;
839
+ height: 10px;
840
+ border-radius: 50%;
841
+ background: rgba(255, 255, 255, 0.5);
842
+ cursor: pointer;
843
+ transition: var(--transition);
844
+ }
845
+
846
+ .carousel-dot.active {
847
+ background: white;
848
+ }
849
+
850
+ .property-header {
851
+ display: flex;
852
+ justify-content: space-between;
853
+ align-items: center;
854
+ }
855
+
856
+ .property-header h2 {
857
+ font-size: 1.8rem;
858
+ font-weight: 700;
859
+ color: var(--text-primary);
860
+ margin: 0 0 10px 0;
861
+ }
862
+
863
+ .property-type {
864
+ display: inline-block;
865
+ padding: 8px 16px;
866
+ background-color: var(--accent-color);
867
+ color: white;
868
+ border-radius: 20px;
869
+ font-size: 0.9rem;
870
+ font-weight: 500;
871
+ }
872
+
873
+ .property-info {
874
+ display: grid;
875
+ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
876
+ gap: 20px;
877
+ padding: 20px 0;
878
+ border-top: 1px solid #E1E8ED;
879
+ border-bottom: 1px solid #E1E8ED;
880
+ max-height: 300px; /* Set a max height for scrolling */
881
+ overflow-y: auto; /* Enable vertical scrolling */
882
+ scrollbar-width: thin; /* For Firefox */
883
+ scrollbar-color: var(--primary-color) var(--secondary-color); /* For Firefox */
884
+ }
885
+
886
+ .property-info::-webkit-scrollbar {
887
+ width: 8px; /* Width of the scrollbar */
888
+ }
889
+
890
+ .property-info::-webkit-scrollbar-track {
891
+ background: var(--secondary-color); /* Color of the scrollbar track */
892
+ border-radius: 10px;
893
+ }
894
+
895
+ .property-info::-webkit-scrollbar-thumb {
896
+ background: var(--primary-color); /* Color of the scrollbar thumb */
897
+ border-radius: 10px;
898
+ }
899
+
900
+ .property-info::-webkit-scrollbar-thumb:hover {
901
+ background: var(--accent-color); /* Color of the scrollbar thumb on hover */
902
+ }
903
+
904
+ .description {
905
+ margin: 10px 0;
906
+ line-height: 1.6;
907
+ color: var(--text-secondary);
908
+ }
909
+
910
+ .key-features {
911
+ display: flex;
912
+ flex-wrap: wrap;
913
+ gap: 10px;
914
+ margin: 10px 0;
915
+ align-items: center;
916
+ }
917
+
918
+ .feature-pill {
919
+ background-color: var(--secondary-color);
920
+ padding: 2px 10px;
921
+ border-radius: 10px;
922
+ font-size: 0.9rem;
923
+ color: var(--text-primary);
924
+ font-weight: 500;
925
+ transition: var(--transition);
926
+ border: 2px solid var(--primary-color); /* Added border */
927
+ }
928
+
929
+ .feature-pill:hover {
930
+ background-color: var(--primary-color);
931
+ color: white;
932
+ transform: translateY(-2px);
933
+ }
934
+
935
+ .amenities-card {
936
+ background-color: var(--secondary-color);
937
+ border-radius: var(--border-radius);
938
+ padding: 20px;
939
+ margin: 10px 0;
940
+ }
941
+
942
+ .amenities-pills {
943
+ display: flex;
944
+ flex-wrap: wrap;
945
+ gap: 10px;
946
+ margin-top: 10px;
947
+ }
948
+
949
+ .amenity-pill {
950
+ background-color: var(--secondary-color);
951
+ padding: 2px 10px;
952
+ border-radius: 10px;
953
+ font-size: 0.9rem;
954
+ color: var(--text-primary);
955
+ font-weight: 500;
956
+ transition: var(--transition);
957
+ border: 2px solid var(--primary-color); /* Added border */
958
+ }
959
+
960
+ .amenity-pill:hover {
961
+ background-color: var(--primary-color);
962
+ color: white;
963
+ transform: translateY(-2px);
964
+ }
965
+
966
+ .construction-status {
967
+ display: flex;
968
+ justify-content: space-between;
969
+ padding-top: 20px;
970
+ color: var(--text-secondary);
971
+ }
972
+
973
+ .accordion {
974
+ background-color: var(--secondary-color);
975
+ border-radius: var(--border-radius);
976
+ box-shadow: var(--box-shadow);
977
+ margin-bottom: 20px;
978
+ overflow: hidden;
979
+ }
980
+
981
+ .accordion-header:hover {
982
+ }
983
+
984
+ .accordion-header .arrow {
985
+ transition: transform 0.3s ease;
986
+ }
987
+
988
+ .accordion-header.active .arrow {
989
+ transform: rotate(90deg);
990
+ }
991
+
992
+ .accordion-header strong {
993
+ font-size: 1.1rem;
994
+ color: var(--text-primary);
995
+ display: flex;
996
+ align-items: center;
997
+ gap: 10px;
998
+ }
999
+
1000
+ .accordion-arrow {
1001
+ transition: transform 0.3s ease;
1002
+ font-size: 0.9rem;
1003
+ color: var(--primary-color);
1004
+ }
1005
+
1006
+ .accordion-arrow.active {
1007
+ transform: rotate(180deg);
1008
+ }
1009
+
1010
+ .accordion-section:last-child {
1011
+ border-bottom: none;
1012
+ }
1013
+
1014
+ .accordion-header.active + .accordion-content {
1015
+ display: block; /* Show content when active */
1016
+ }
1017
+
1018
+ .quick-keywords::-webkit-scrollbar {
1019
+ display: none;
1020
+ }
1021
+
1022
+ .quick-keyword {
1023
+ flex: 0 0 auto; /* Prevent buttons from shrinking */
1024
+ padding: 10px 15px;
1025
+ border-radius: 50px;
1026
+ border: none;
1027
+ color: white;
1028
+ cursor: pointer;
1029
+ white-space: nowrap;
1030
+ }
1031
+ </style>
1032
+ </head>
1033
+ <body>
1034
+ <h1>HIVE PROP</h1>
1035
+
1036
+ <!-- Property Search Section -->
1037
+ <div class="search-container">
1038
+ <form id="queryForm">
1039
+ <input type="text" id="userQuery" placeholder="Search for your dream property..." required>
1040
+ <button type="button" id="microphoneButton">
1041
+ <i class="fas fa-microphone"></i>
1042
+ </button>
1043
+ <button type="submit">Search Properties</button>
1044
+ </form>
1045
+ </div>
1046
+ <div id="results"></div>
1047
+ <div id="errorMessage" class="error-message"></div>
1048
+ <div id="loadingMessage" style="display: none;">
1049
+ <div class="loading-spinner"></div>
1050
+ <!--<div class="loading-message">Loading...</div>-->
1051
+ </div>
1052
+ <div id="listeningMessage" style="display: none;">
1053
+ <div class="loading-spinner"></div>
1054
+ <div class="loading-message">Listening...</div>
1055
+ </div>
1056
+
1057
+ <!-- Chat Assistant and Recommendations Container -->
1058
+ <div class="chatbot-container">
1059
+ <!-- Chat Assistant Icon -->
1060
+ <div class="chatbot-icon" id="chatbot-icon" style="background-color: #31511E;">
1061
+ <i class="fas fa-comment"></i>
1062
+ </div>
1063
+
1064
+ <!-- Recommendations Icon -->
1065
+ <div class="chatbot-icon" id="recommend-icon" style="background-color: #859F3D;">
1066
+ <i class="fas fa-search"></i>
1067
+ </div>
1068
+ </div>
1069
+
1070
+ <!-- Chat Assistant Container -->
1071
+ <div class="chat-container" id="chat-container" style="left: 2rem;">
1072
+ <div class="chat-header">
1073
+ <img src="/api/placeholder/32/32" alt="Bot Avatar">
1074
+ <span>Hive Prop Chat Bot</span>
1075
+ <button class="close-button">
1076
+ <i class="fas fa-times"></i>
1077
+ </button>
1078
+ </div>
1079
+
1080
+ <div class="chat-body" id="chat-body">
1081
+ <div class="message bot-message">
1082
+ <div class="message-content">
1083
+ Hello! I'm your real estate recommendation assistant. How can I help you today? Please reply with 'hi' to access your location.
1084
+ </div>
1085
+ <div class="timestamp">Now</div>
1086
+ </div>
1087
+ <div class="typing-indicator" id="typing-indicator">
1088
+ <div class="typing-dot"></div>
1089
+ <div class="typing-dot"></div>
1090
+ <div class="typing-dot"></div>
1091
+ </div>
1092
+ </div>
1093
+
1094
+ <div class="chat-footer">
1095
+ <div class="input-group">
1096
+ <input type="text" class="chat-input" id="user-input" placeholder="Type your message..." required>
1097
+ <button class="send-chatbutton" id="send-button">
1098
+ <i class="fas fa-paper-plane"></i>
1099
+ </button>
1100
+ <button type="button" style="padding: 10px 15px;border-radius: 100px;" id="chatMicrophoneButton">
1101
+ <i class="fas fa-microphone"></i>
1102
+ </button>
1103
+ </div>
1104
+ <div class="quick-keywords">
1105
+ <button class="quick-keyword" data-message="Show me nearby properties">Nearby Properties</button>
1106
+ <button class="quick-keyword" data-message="Find luxury homes">Luxury Homes</button>
1107
+ <button class="quick-keyword" data-message="Affordable apartments">Affordable Apartments</button>
1108
+ <button class="quick-keyword" data-message="Properties with pools">Properties with Pools</button>
1109
+ </div>
1110
+ </div>
1111
+ </div>
1112
+
1113
+ <!-- Recommendations Container -->
1114
+ <div class="chat-container" id="recommend-container" style="right: 2rem;">
1115
+ <div class="chat-header">
1116
+ <img src="/content/sample_data/hive_prop.jpg" alt="Bot Avatar">
1117
+ <span>Hive Prop Chatbot</span>
1118
+ <button class="close-button">
1119
+ <i class="fas fa-times"></i>
1120
+ </button>
1121
+ </div>
1122
+
1123
+ <div class="chat-body" id="recommend-body">
1124
+ <div class="message bot-message">
1125
+ <div class="message-content">
1126
+ Hello! I'm your real estate recommendation assistant. How can I help you today? Please reply with 'hi' to access your location.
1127
+ </div>
1128
+ <div class="timestamp">Now</div>
1129
+ </div>
1130
+ <div class="typing-indicator" id="recommend-typing-indicator">
1131
+ <div class="typing-dot"></div>
1132
+ <div class="typing-dot"></div>
1133
+ <div class="typing-dot"></div>
1134
+ </div>
1135
+ </div>
1136
+
1137
+ <div class="chat-footer">
1138
+ <div class="input-group">
1139
+ <input type="text" class="chat-input" id="recommend-input" placeholder="Type your message..." required>
1140
+ <button class="send-chatbutton" id="recommend-send-button">
1141
+ <i class="fas fa-paper-plane"></i>
1142
+ </button>
1143
+ <button type="button" style="padding: 10px 15px;border-radius: 100px;" id="recommendMicrophoneButton">
1144
+ <i class="fas fa-microphone"></i>
1145
+ </button>
1146
+ </div>
1147
+ <div class="quick-keywords" style="
1148
+ border-radius:50px;
1149
+ display: flex;
1150
+ flex-direction: row;
1151
+ overflow-x: auto;
1152
+ white-space: nowrap;
1153
+ gap: 10px;
1154
+ padding: 10px;
1155
+ scrollbar-width: none; /* Hide scrollbar for Firefox */
1156
+ -ms-overflow-style: none; /* Hide scrollbar for IE/Edge */
1157
+ position: relative;
1158
+ background: white;
1159
+ box-shadow: inset 20px 0 20px -10px rgba(0, 0, 0, 0.5), inset -20px 0 20px -10px rgba(0, 0, 0, 0.5);
1160
+ ">
1161
+ <button class="quick-keyword" data-message="Show me nearby properties">Nearby Properties</button>
1162
+ <button class="quick-keyword" data-message="Find luxury homes">Luxury Homes</button>
1163
+ <button class="quick-keyword" data-message="Affordable apartments">Affordable Apartments</button>
1164
+ <button class="quick-keyword" data-message="Properties with pools">Properties with Pools</button>
1165
+ <button class="quick-keyword" data-message="Pet-friendly rentals">Pet-friendly Rentals</button>
1166
+ <button class="quick-keyword" data-message="Beachfront properties">Beachfront Properties</button>
1167
+ </div>
1168
+ </div>
1169
+ </div>
1170
+
1171
+ <script>
1172
+ // Property Search Scripts
1173
+ $(document).ready(function() {
1174
+ $('#queryForm').on('submit', function(event) {
1175
+ event.preventDefault();
1176
+ const query = $('#userQuery').val();
1177
+ $('#results').empty();
1178
+ $('#errorMessage').empty();
1179
+ $('#loadingMessage').show();
1180
+
1181
+ $.ajax({
1182
+ url: '/search',
1183
+ type: 'POST',
1184
+ contentType: 'application/json',
1185
+ data: JSON.stringify({ query: query }),
1186
+ success: function(data) {
1187
+ $('#loadingMessage').hide();
1188
+ if (data.error) {
1189
+ $('#errorMessage').text('Error: ' + data.error);
1190
+ } else {
1191
+ data.forEach(function(property) {
1192
+ const propertyElement = $(`
1193
+ <div class="property">
1194
+ <div class="image-container">
1195
+ <div class="carousel">
1196
+ <div class="carousel">
1197
+ <div class="carousel-images">
1198
+ <img src="${property['Property Image']}" alt="${property['Property Name']}" class="carousel-image">
1199
+ </div>
1200
+ </div>
1201
+ </div>
1202
+ <button class="favorite-button">
1203
+ <i class="fas fa-heart"></i>
1204
+ </button>
1205
+ </div>
1206
+ <div class="property-details">
1207
+ <div class="property-header">
1208
+ <h2>${property["Property Name"]}</h2>
1209
+ <span class="property-type">${property["PropertyType"]}</span>
1210
+ </div>
1211
+ <div>
1212
+ <span>
1213
+ <strong>Location</strong>
1214
+ ${property["Address"]}, ${property["City"]}, ${property["State"]}, ${property["Country"]}
1215
+ </span>
1216
+ <span>
1217
+ <strong>Zip Code</strong>
1218
+ ${property["ZipCode"]}
1219
+ </span>
1220
+ </div>
1221
+ <div class="property-info">
1222
+ <div class="scrollable-info" style="
1223
+ display: flex;
1224
+ justify-content: space-between"> <span>
1225
+ <strong>Market Value</strong><br>
1226
+ ${property["MarketValue"]}
1227
+ </span>
1228
+ <span>
1229
+ <strong>Total Square Feet</strong><br>
1230
+ ${property["TotalSquareFeet"]} sq ft
1231
+ </span>
1232
+ <span>
1233
+ <strong>Bedrooms</strong><br>
1234
+ ${property["Beds"]}
1235
+ </span>
1236
+ <span>
1237
+ <strong>Bathrooms</strong><br>
1238
+ ${property["Baths"]}
1239
+ </span>
1240
+ <span>
1241
+ <strong>Contact</strong><br>
1242
+ ${property["Contact"]}
1243
+ </span>
1244
+ </div>
1245
+ </div>
1246
+ <div class="accordion-section">
1247
+ <div class="accordion-header">
1248
+ <strong>Description</strong>
1249
+ <i class="fas fa-chevron-down accordion-arrow"></i>
1250
+ </div>
1251
+ <div class="accordion-content">
1252
+ <p>${property["Description"]}</p>
1253
+ </div>
1254
+ </div>
1255
+ <div class="accordion-section">
1256
+ <div class="accordion-header">
1257
+ <strong>Key Features</strong>
1258
+ <i class="fas fa-chevron-down accordion-arrow"></i>
1259
+ </div>
1260
+ <div class="accordion-content">
1261
+ <div class="key-features">
1262
+ ${property["KeyFeatures"].split(', ').map(feature => `
1263
+ <span class="feature-pill">${feature}</span>
1264
+ `).join('')}
1265
+ </div>
1266
+ </div>
1267
+ </div>
1268
+ <div class="accordion-section">
1269
+ <div class="accordion-header">
1270
+ <strong>Nearby Amenities</strong>
1271
+ <i class="fas fa-chevron-down accordion-arrow"></i>
1272
+ </div>
1273
+ <div class="accordion-content">
1274
+ <div class="amenities-pills">
1275
+ ${property["NearbyAmenities"].split(', ').map(amenity => `
1276
+ <span class="amenity-pill">${amenity}</span>
1277
+ `).join('')}
1278
+ </div>
1279
+ </div>
1280
+ </div>
1281
+ <div class="construction-status">
1282
+ <p><strong>Property Status:</strong> ${property["PropertyStatus"]}</p>
1283
+ <p><strong>Year Built:</strong> ${property["YearBuilt"]}</p>
1284
+ </div>
1285
+ <div class="accordion-section">
1286
+ <div class="accordion-header">
1287
+ <strong>Agent Details</strong>
1288
+ <i class="fas fa-chevron-down accordion-arrow"></i>
1289
+ </div>
1290
+ <div class="accordion-content">
1291
+ <div
1292
+ style="display: flex; justify-content: space-between"> <span>
1293
+ <strong>Agent Name</strong><br>
1294
+ ${property["AgentName"]}
1295
+ </span>
1296
+ <span>
1297
+ <strong>Agent Phone Number</strong><br>
1298
+ ${property["AgentPhoneNumber"]}
1299
+ </span>
1300
+ <span>
1301
+ <strong>Agent Email</strong><br>
1302
+ ${property["AgentEmail"]}
1303
+ </span>
1304
+ </div>
1305
+ </div>
1306
+ </div>
1307
+ </div>
1308
+ </div>
1309
+ `);
1310
+ $('#results').append(propertyElement);
1311
+
1312
+ propertyElement.find('.accordion-header').each(function() {
1313
+ $(this).on('click', function() {
1314
+ const $header = $(this);
1315
+ const $content = $header.next('.accordion-content');
1316
+ const $arrow = $header.find('.accordion-arrow');
1317
+
1318
+ $content.slideToggle(300);
1319
+ $arrow.toggleClass('active');
1320
+
1321
+ const $otherHeaders = $header.closest('.property-details')
1322
+ .find('.accordion-header').not($header);
1323
+
1324
+ $otherHeaders.each(function() {
1325
+ $(this).next('.accordion-content').slideUp(300);
1326
+ $(this).find('.accordion-arrow').removeClass('active');
1327
+ });
1328
+ });
1329
+ });
1330
+
1331
+ propertyElement.find('.favorite-button').on('click', function() {
1332
+ $(this).toggleClass('active');
1333
+ });
1334
+ });
1335
+ }
1336
+ },
1337
+ error: function() {
1338
+ $('#loadingMessage').hide();
1339
+ $('#errorMessage').text('Error: Unable to fetch data. Please try again later.');
1340
+ }
1341
+ });
1342
+ });
1343
+
1344
+ $('#queryForm').on('submit', function() {
1345
+ $('html, body').animate({
1346
+ scrollTop: $('#results').offset().top - 20
1347
+ }, 1000);
1348
+ });
1349
+
1350
+ $('#userQuery').on('focus', function() {
1351
+ $(this).parent().addClass('focused');
1352
+ }).on('blur', function() {
1353
+ $(this).parent().removeClass('focused');
1354
+ });
1355
+
1356
+ $(window).on('resize', function() {
1357
+ if ($(window).width() <= 768) {
1358
+ $('.property').addClass('mobile-view');
1359
+ } else {
1360
+ $('.property').removeClass('mobile-view');
1361
+ }
1362
+ });
1363
+
1364
+ $('[data-tooltip]').each(function() {
1365
+ $(this).tooltip({
1366
+ placement: 'top',
1367
+ title: $(this).data('tooltip')
1368
+ });
1369
+ });
1370
+
1371
+ if ('IntersectionObserver' in window) {
1372
+ const imageObserver = new IntersectionObserver((entries, observer) => {
1373
+ entries.forEach(entry => {
1374
+ if (entry.isIntersecting) {
1375
+ const img = entry.target;
1376
+ img.src = img.dataset.src;
1377
+ img.removeAttribute('data-src');
1378
+ observer.unobserve(img);
1379
+ }
1380
+ });
1381
+ });
1382
+
1383
+ document.querySelectorAll('img[data-src]').forEach(img => {
1384
+ imageObserver.observe(img);
1385
+ });
1386
+ }
1387
+
1388
+ const microphoneButton = document.getElementById("microphoneButton");
1389
+ const recognizer = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
1390
+ recognizer.lang = 'en-US';
1391
+ recognizer.continuous = true;
1392
+ recognizer.interimResults = true;
1393
+
1394
+ let silenceTimer = null;
1395
+ const SILENCE_DURATION = 3000;
1396
+
1397
+ microphoneButton.addEventListener("click", () => {
1398
+ microphoneButton.classList.add('listening');
1399
+ $('#listeningMessage').show();
1400
+ recognizer.start();
1401
+ console.log("Listening...");
1402
+ });
1403
+
1404
+ recognizer.onresult = function(event) {
1405
+ clearTimeout(silenceTimer);
1406
+
1407
+ let finalTranscript = '';
1408
+ for (let i = event.resultIndex; i < event.results.length; i++) {
1409
+ if (event.results[i].isFinal) {
1410
+ finalTranscript += event.results[i][0].transcript;
1411
+ }
1412
+ }
1413
+
1414
+ if (finalTranscript) {
1415
+ $('#userQuery').val(finalTranscript);
1416
+ console.log("Transcript: ", finalTranscript);
1417
+ }
1418
+
1419
+ silenceTimer = setTimeout(() => {
1420
+ recognizer.stop();
1421
+ console.log("Stopped listening due to silence");
1422
+ }, SILENCE_DURATION);
1423
+ };
1424
+
1425
+ recognizer.onend = function() {
1426
+ console.log("Speech recognition service disconnected");
1427
+ $('#listeningMessage').hide();
1428
+ microphoneButton.classList.remove('listening');
1429
+ clearTimeout(silenceTimer);
1430
+
1431
+ if ($('#userQuery').val().trim()) {
1432
+ $('#queryForm').submit();
1433
+ }
1434
+ };
1435
+
1436
+ recognizer.onerror = function(event) {
1437
+ console.error("Speech recognition error", event.error);
1438
+ $('#listeningMessage').hide();
1439
+ microphoneButton.classList.remove('listening');
1440
+ clearTimeout(silenceTimer);
1441
+ };
1442
+
1443
+ document.getElementById("chatbot-icon").addEventListener("click", function() {
1444
+ const chatContainer = document.getElementById("chat-container");
1445
+ chatContainer.style.display = chatContainer.style.display === "none" || chatContainer.style.display === "" ? "flex" : "none";
1446
+ });
1447
+
1448
+ const chatBody = document.getElementById("chat-body");
1449
+ const userInput = document.getElementById("user-input");
1450
+ const sendButton = document.getElementById("send-button");
1451
+ const typingIndicator = document.getElementById("typing-indicator");
1452
+
1453
+ function addMessage(content, isUser = false) {
1454
+ const messageDiv = document.createElement("div");
1455
+ messageDiv.className = `message ${isUser ? "user-message" : "bot-message"}`;
1456
+
1457
+ const messageContent = document.createElement("div");
1458
+ messageContent.className = "message-content";
1459
+ messageContent.innerHTML = formatMessageContent(content);
1460
+
1461
+ const timestamp = document.createElement("div");
1462
+ timestamp.className = "timestamp";
1463
+ timestamp.textContent = new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
1464
+
1465
+ messageDiv.appendChild(messageContent);
1466
+ messageDiv.appendChild(timestamp);
1467
+
1468
+ chatBody.insertBefore(messageDiv, typingIndicator);
1469
+ chatBody.scrollTop = chatBody.scrollHeight;
1470
+ }
1471
+
1472
+ function handleUserInput() {
1473
+ const message = userInput.value.trim().toLowerCase();
1474
+ if (!message) return;
1475
+
1476
+ addMessage(message, true);
1477
+ userInput.value = "";
1478
+ typingIndicator.style.display = "block";
1479
+
1480
+ if (message === 'hi') {
1481
+ if (navigator.geolocation) {
1482
+ navigator.geolocation.getCurrentPosition(function(position) {
1483
+ const latitude = position.coords.latitude;
1484
+ const longitude = position.coords.longitude;
1485
+ console.log("User Location:", latitude, longitude);
1486
+
1487
+ fetch("/set-location", {
1488
+ method: "POST",
1489
+ headers: {
1490
+ "Content-Type": "application/json",
1491
+ },
1492
+ body: JSON.stringify({ latitude: latitude, longitude: longitude, session_id: 'chat-session' })
1493
+ })
1494
+ .then(response => response.json())
1495
+ .then(data => {
1496
+ console.log("Location set:", data);
1497
+ const city = data.city;
1498
+ const state = data.state;
1499
+ const country = data.country;
1500
+ addMessage(`Location set successfully in ${city}, ${state}, ${country}. Would you like to see nearby properties? Please reply with 'yes' or 'no'.`);
1501
+ typingIndicator.style.display = "none";
1502
+ })
1503
+ .catch(error => {
1504
+ console.error("Error setting location:", error);
1505
+ addMessage("Unable to access your location. Please try again.");
1506
+ typingIndicator.style.display = "none";
1507
+ });
1508
+ }, function(error) {
1509
+ console.error("Error getting user location:", error);
1510
+ addMessage("Unable to access your location. Please try again.");
1511
+ typingIndicator.style.display = "none";
1512
+ });
1513
+ } else {
1514
+ console.error("Geolocation is not supported by this browser.");
1515
+ addMessage("Geolocation is not supported by your browser.");
1516
+ typingIndicator.style.display = "none";
1517
+ }
1518
+ } else if (message === 'yes') {
1519
+ fetch("/recommend", {
1520
+ method: "POST",
1521
+ headers: {
1522
+ "Content-Type": "application/json",
1523
+ },
1524
+ body: JSON.stringify({ query: message, session_id: 'chat-session' })
1525
+ })
1526
+ .then(response => response.json())
1527
+ .then(data => {
1528
+ if (data.properties) {
1529
+ let propertiesMessage = "Here are the 5 nearest properties to your location:\n";
1530
+ data.properties.forEach(property => {
1531
+ propertiesMessage += `* **${property.PropertyName}** at ${property.Address}, ${property.City}\n`;
1532
+ propertiesMessage += ` Type: ${property.PropertyType}\n`; // Added property type
1533
+ propertiesMessage += ` (Distance: ${property.Distance} miles)\n\n`; // Added a break before the distance
1534
+ });
1535
+ addMessage(propertiesMessage);
1536
+ } else {
1537
+ addMessage(data.response);
1538
+ }
1539
+ typingIndicator.style.display = "none";
1540
+ })
1541
+
1542
+ .catch(error => {
1543
+ console.error("Error:", error);
1544
+ addMessage("I apologize, but I encountered an error. Could you please try again?");
1545
+ typingIndicator.style.display = "none";
1546
+ });
1547
+ } else {
1548
+ fetch("/generate", {
1549
+ method: "POST",
1550
+ headers: {
1551
+ "Content-Type": "application/json",
1552
+ },
1553
+ body: JSON.stringify({ query: message, session_id: 'chat-session' })
1554
+ })
1555
+ .then(response => response.json())
1556
+ .then(data => {
1557
+ addMessage(data.response);
1558
+ typingIndicator.style.display = "none";
1559
+ })
1560
+ .catch(error => {
1561
+ console.error("Error:", error);
1562
+ addMessage("I apologize, but I encountered an error. Could you please try again?");
1563
+ typingIndicator.style.display = "none";
1564
+ });
1565
+ }
1566
+ }
1567
+
1568
+ sendButton.addEventListener("click", handleUserInput);
1569
+ userInput.addEventListener("keypress", function(event) {
1570
+ if (event.key === "Enter") {
1571
+ handleUserInput();
1572
+ }
1573
+ });
1574
+
1575
+ const chatMicrophoneButton = document.getElementById("chatMicrophoneButton");
1576
+ const chatRecognizer = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
1577
+ chatRecognizer.lang = 'en-US';
1578
+ chatRecognizer.continuous = true;
1579
+ chatRecognizer.interimResults = true;
1580
+
1581
+ let chatSilenceTimer = null;
1582
+
1583
+ chatMicrophoneButton.addEventListener("click", () => {
1584
+ chatMicrophoneButton.classList.add('listening');
1585
+ $('#listeningMessage').show();
1586
+ chatRecognizer.start();
1587
+ console.log("Chat listening...");
1588
+ });
1589
+
1590
+ chatRecognizer.onresult = function(event) {
1591
+ clearTimeout(chatSilenceTimer);
1592
+
1593
+ let finalTranscript = '';
1594
+ for (let i = event.resultIndex; i < event.results.length; i++) {
1595
+ if (event.results[i].isFinal) {
1596
+ finalTranscript += event.results[i][0].transcript;
1597
+ }
1598
+ }
1599
+
1600
+ if (finalTranscript) {
1601
+ userInput.value = finalTranscript;
1602
+ console.log("Chat Transcript: ", finalTranscript);
1603
+ }
1604
+
1605
+ chatSilenceTimer = setTimeout(() => {
1606
+ chatRecognizer.stop();
1607
+ console.log("Stopped chat listening due to silence");
1608
+ }, SILENCE_DURATION);
1609
+ };
1610
+
1611
+ chatRecognizer.onend = function() {
1612
+ console.log("Chat speech recognition service disconnected");
1613
+ $('#listeningMessage').hide();
1614
+ chatMicrophoneButton.classList.remove('listening');
1615
+ clearTimeout(chatSilenceTimer);
1616
+
1617
+ if (userInput.value.trim()) {
1618
+ handleUserInput();
1619
+ }
1620
+ };
1621
+
1622
+ chatRecognizer.onerror = function(event) {
1623
+ console.error("Chat speech recognition error", event.error);
1624
+ $('#listeningMessage').hide();
1625
+ chatMicrophoneButton.classList.remove('listening');
1626
+ clearTimeout(chatSilenceTimer);
1627
+ };
1628
+
1629
+ document.getElementById("recommend-icon").addEventListener("click", function() {
1630
+ const recommendContainer = document.getElementById("recommend-container");
1631
+ recommendContainer.style.display = recommendContainer.style.display === "none" || recommendContainer.style.display === "" ? "flex" : "none";
1632
+ });
1633
+
1634
+ const recommendBody = document.getElementById("recommend-body");
1635
+ const recommendInput = document.getElementById("recommend-input");
1636
+ const recommendSendButton = document.getElementById("recommend-send-button");
1637
+ const recommendTypingIndicator = document.getElementById("recommend-typing-indicator");
1638
+
1639
+ function addRecommendMessage(content, isUser = false) {
1640
+ const messageDiv = document.createElement("div");
1641
+ messageDiv.className = `message ${isUser ? "user-message" : "bot-message"}`;
1642
+
1643
+ const messageContent = document.createElement("div");
1644
+ messageContent.className = "message-content";
1645
+ messageContent.innerHTML = formatMessageContent(content);
1646
+
1647
+ const timestamp = document.createElement("div");
1648
+ timestamp.className = "timestamp";
1649
+ timestamp.textContent = new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
1650
+
1651
+ messageDiv.appendChild(messageContent);
1652
+ messageDiv.appendChild(timestamp);
1653
+
1654
+ recommendBody.insertBefore(messageDiv, recommendTypingIndicator);
1655
+ recommendBody.scrollTop = recommendBody.scrollHeight;
1656
+ }
1657
+
1658
+ function handleRecommendInput() {
1659
+ const message = recommendInput.value.trim().toLowerCase();
1660
+ if (!message) return;
1661
+
1662
+ addRecommendMessage(message, true);
1663
+ recommendInput.value = "";
1664
+ recommendTypingIndicator.style.display = "block";
1665
+
1666
+ if (message === 'hi') {
1667
+ if (navigator.geolocation) {
1668
+ navigator.geolocation.getCurrentPosition(function(position) {
1669
+ const latitude = position.coords.latitude;
1670
+ const longitude = position.coords.longitude;
1671
+ console.log("User Location:", latitude, longitude);
1672
+
1673
+ fetch("/set-location", {
1674
+ method: "POST",
1675
+ headers: {
1676
+ "Content-Type": "application/json",
1677
+ },
1678
+ body: JSON.stringify({ latitude: latitude, longitude: longitude, session_id: 'recommend-session' })
1679
+ })
1680
+ .then(response => response.json())
1681
+ .then(data => {
1682
+ console.log("Location set:", data);
1683
+ const city = data.city;
1684
+ const state = data.state;
1685
+ const country = data.country;
1686
+ addRecommendMessage(`Location set successfully in ${city}, ${state}, ${country}. Would you like to see nearby properties? Please reply with 'yes' or 'no'.`);
1687
+ recommendTypingIndicator.style.display = "none";
1688
+ })
1689
+ .catch(error => {
1690
+ console.error("Error setting location:", error);
1691
+ addRecommendMessage("Unable to access your location. Please try again.");
1692
+ recommendTypingIndicator.style.display = "none";
1693
+ });
1694
+ }, function(error) {
1695
+ console.error("Error getting user location:", error);
1696
+ addRecommendMessage("Unable to access your location. Please try again.");
1697
+ recommendTypingIndicator.style.display = "none";
1698
+ });
1699
+ } else {
1700
+ console.error("Geolocation is not supported by this browser.");
1701
+ addRecommendMessage("Geolocation is not supported by your browser.");
1702
+ recommendTypingIndicator.style.display = "none";
1703
+ }
1704
+ } else if (message === 'yes') {
1705
+ fetch("/recommend", {
1706
+ method: "POST",
1707
+ headers: {
1708
+ "Content-Type": "application/json",
1709
+ },
1710
+ body: JSON.stringify({ query: message, session_id: 'recommend-session' })
1711
+ })
1712
+ .then(response => response.json())
1713
+ .then(data => {
1714
+ if (data.properties) {
1715
+ let propertiesMessage = "Here are the 5 nearest properties to your location:\n";
1716
+ data.properties.forEach(property => {
1717
+ propertiesMessage += `**${property.PropertyName}** at ${property.Address}, ${property.City}\n`;
1718
+ propertiesMessage += ` Type: ${property.PropertyType}\n`; // Added property type
1719
+ propertiesMessage += ` (Distance: ${property.Distance} miles)\n\n`; // Added a break before the distance
1720
+ });
1721
+ addRecommendMessage(propertiesMessage);
1722
+ } else {
1723
+ addRecommendMessage(data.response);
1724
+ }
1725
+ recommendTypingIndicator.style.display = "none";
1726
+ })
1727
+
1728
+ .catch(error => {
1729
+ console.error("Error:", error);
1730
+ addRecommendMessage("I apologize, but I encountered an error. Could you please try again?");
1731
+ recommendTypingIndicator.style.display = "none";
1732
+ });
1733
+ } else {
1734
+ fetch("/recommend", {
1735
+ method: "POST",
1736
+ headers: {
1737
+ "Content-Type": "application/json",
1738
+ },
1739
+ body: JSON.stringify({ query: message, session_id: 'recommend-session' })
1740
+ })
1741
+ .then(response => response.json())
1742
+ .then(data => {
1743
+ addRecommendMessage(data.response);
1744
+ recommendTypingIndicator.style.display = "none";
1745
+ })
1746
+ .catch(error => {
1747
+ console.error("Error:", error);
1748
+ addRecommendMessage("I apologize, but I encountered an error. Could you please try again?");
1749
+ recommendTypingIndicator.style.display = "none";
1750
+ });
1751
+ }
1752
+ }
1753
+
1754
+ recommendSendButton.addEventListener("click", handleRecommendInput);
1755
+ recommendInput.addEventListener("keypress", function(event) {
1756
+ if (event.key === "Enter") {
1757
+ handleRecommendInput();
1758
+ }
1759
+ });
1760
+
1761
+ const recommendMicrophoneButton = document.getElementById("recommendMicrophoneButton");
1762
+ const recommendRecognizer = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
1763
+ recommendRecognizer.lang = 'en-US';
1764
+ recommendRecognizer.continuous = true;
1765
+ recommendRecognizer.interimResults = true;
1766
+
1767
+ let recommendSilenceTimer = null;
1768
+
1769
+ recommendMicrophoneButton.addEventListener("click", () => {
1770
+ recommendMicrophoneButton.classList.add('listening');
1771
+ $('#listeningMessage').show();
1772
+ recommendRecognizer.start();
1773
+ console.log("Recommend listening...");
1774
+ });
1775
+
1776
+ recommendRecognizer.onresult = function(event) {
1777
+ clearTimeout(recommendSilenceTimer);
1778
+
1779
+ let finalTranscript = '';
1780
+ for (let i = event.resultIndex; i < event.results.length; i++) {
1781
+ if (event.results[i].isFinal) {
1782
+ finalTranscript += event.results[i][0].transcript;
1783
+ }
1784
+ }
1785
+
1786
+ if (finalTranscript) {
1787
+ recommendInput.value = finalTranscript;
1788
+ console.log("Recommend Transcript: ", finalTranscript);
1789
+ }
1790
+
1791
+ recommendSilenceTimer = setTimeout(() => {
1792
+ recommendRecognizer.stop();
1793
+ console.log("Stopped recommend listening due to silence");
1794
+ }, SILENCE_DURATION);
1795
+ };
1796
+
1797
+ recommendRecognizer.onend = function() {
1798
+ console.log("Recommend speech recognition service disconnected");
1799
+ $('#listeningMessage').hide();
1800
+ recommendMicrophoneButton.classList.remove('listening');
1801
+ clearTimeout(recommendSilenceTimer);
1802
+
1803
+ if (recommendInput.value.trim()) {
1804
+ handleRecommendInput();
1805
+ }
1806
+ };
1807
+
1808
+ recommendRecognizer.onerror = function(event) {
1809
+ console.error("Recommend speech recognition error", event.error);
1810
+ $('#listeningMessage').hide();
1811
+ recommendMicrophoneButton.classList.remove('listening');
1812
+ clearTimeout(recommendSilenceTimer);
1813
+ };
1814
+
1815
+ function formatMessageContent(content) {
1816
+ content = content.replace(/\n/g, '<br>');
1817
+ content = content.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
1818
+ return content;
1819
+ }
1820
+
1821
+ document.querySelectorAll('.quick-keyword').forEach(button => {
1822
+ button.addEventListener('click', function() {
1823
+ const message = this.getAttribute('data-message');
1824
+ if (this.closest('#chat-container')) {
1825
+ userInput.value = message;
1826
+ handleUserInput();
1827
+ } else if (this.closest('#recommend-container')) {
1828
+ recommendInput.value = message;
1829
+ handleRecommendInput();
1830
+ }
1831
+ });
1832
+ });
1833
+ });
1834
+ </script>
1835
+
1836
+ </body>
1837
+ </html>
1838
+