Subversion Repositories SmartDukaan

Rev

Rev 36632 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
36621 ranu 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">
6
	<title>Route Planner - Smart Dukaan</title>
7
	<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
8
	<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
9
	<style>
10
		* {
11
			margin: 0;
12
			padding: 0;
13
			box-sizing: border-box;
14
		}
15
 
16
		body {
17
			font-family: 'Inter', sans-serif;
18
			background: #0f172a;
19
			color: #e2e8f0;
20
			height: 100vh;
21
			overflow: hidden;
22
		}
23
 
24
		/* Top Bar */
25
		.top-bar {
26
			display: flex;
27
			align-items: center;
28
			gap: 12px;
29
			padding: 8px 16px;
30
			background: #1e293b;
31
			border-bottom: 1px solid #334155;
32
			height: 50px;
33
		}
34
 
35
		.top-bar h1 {
36
			font-size: 16px;
37
			font-weight: 600;
38
			color: #60a5fa;
39
			margin-right: 20px;
40
		}
41
 
42
		.top-bar select, .top-bar button {
43
			font-family: inherit;
44
			font-size: 13px;
45
			padding: 6px 10px;
46
			border-radius: 6px;
47
			border: 1px solid #475569;
48
			background: #1e293b;
49
			color: #e2e8f0;
50
		}
51
 
52
		.top-bar select:focus {
53
			outline: none;
54
			border-color: #60a5fa;
55
		}
56
 
57
		.top-bar button {
58
			cursor: pointer;
59
			font-weight: 500;
60
		}
61
 
62
		.top-bar .btn-primary {
63
			background: #3b82f6;
64
			border-color: #3b82f6;
65
			color: #fff;
66
		}
67
 
68
		.top-bar .btn-primary:hover {
69
			background: #2563eb;
70
		}
71
 
72
		/* Main Layout */
73
		.main-layout {
74
			display: flex;
75
			height: calc(100vh - 50px);
76
		}
77
 
78
		/* Left Panel */
79
		.left-panel {
80
			width: 300px;
81
			min-width: 300px;
82
			background: #1e293b;
83
			border-right: 1px solid #334155;
84
			display: flex;
85
			flex-direction: column;
86
			overflow: hidden;
87
		}
88
 
89
		.panel-tabs {
90
			display: flex;
91
			border-bottom: 1px solid #334155;
92
		}
93
 
94
		.panel-tab {
95
			flex: 1;
96
			padding: 10px;
97
			text-align: center;
98
			font-size: 12px;
99
			font-weight: 600;
100
			cursor: pointer;
101
			color: #94a3b8;
102
			border-bottom: 2px solid transparent;
103
			transition: all 0.2s;
104
		}
105
 
106
		.panel-tab.active {
107
			color: #60a5fa;
108
			border-bottom-color: #60a5fa;
109
		}
110
 
111
		.panel-tab:hover {
112
			color: #e2e8f0;
113
		}
114
 
115
		.panel-content {
116
			flex: 1;
117
			overflow-y: auto;
118
			padding: 10px;
119
		}
120
 
121
		/* Route List */
122
		.route-day {
123
			margin-bottom: 12px;
124
		}
125
 
126
		.route-day-header {
127
			font-size: 12px;
128
			font-weight: 600;
129
			color: #60a5fa;
130
			padding: 6px 8px;
131
			background: #0f172a;
132
			border-radius: 6px;
133
			display: flex;
134
			justify-content: space-between;
135
		}
136
 
137
		.route-stop {
138
			display: flex;
139
			align-items: center;
140
			gap: 8px;
141
			padding: 6px 8px;
142
			border-left: 2px solid #334155;
143
			margin-left: 12px;
144
			font-size: 12px;
145
		}
146
 
147
		.route-stop .stop-num {
148
			width: 20px;
149
			height: 20px;
150
			border-radius: 50%;
151
			background: #3b82f6;
152
			color: #fff;
153
			display: flex;
154
			align-items: center;
155
			justify-content: center;
156
			font-size: 10px;
157
			font-weight: 700;
158
			flex-shrink: 0;
159
		}
160
 
161
		.route-stop .stop-info {
162
			flex: 1;
163
		}
164
 
165
		.route-stop .stop-name {
166
			font-weight: 500;
167
			color: #e2e8f0;
168
		}
169
 
170
		.route-stop .stop-meta {
171
			color: #64748b;
172
			font-size: 11px;
173
		}
174
 
175
		.route-stop-home {
176
			border-left-color: #22c55e;
177
		}
178
 
179
		.route-stop-home .stop-num {
180
			background: #22c55e;
181
		}
182
 
183
		.route-stop-clickable:hover {
184
			background: #334155;
185
			border-radius: 4px;
186
		}
187
 
188
		.stop-remove {
189
			color: #64748b;
190
			font-size: 16px;
191
			font-weight: 700;
192
			cursor: pointer;
193
			padding: 0 4px;
194
			flex-shrink: 0;
195
			line-height: 1;
196
		}
197
 
198
		.stop-remove:hover {
199
			color: #ef4444;
200
		}
201
 
202
		/* Distance Segment between stops */
203
		.route-segment {
204
			display: flex;
205
			align-items: center;
206
			margin-left: 20px;
207
			padding: 2px 0;
208
		}
209
 
210
		.seg-line {
211
			width: 12px;
212
			border-top: 1px dashed #475569;
213
			margin-right: 6px;
214
		}
215
 
216
		.seg-line-home {
217
			border-top-color: #22c55e;
218
		}
219
 
220
		.seg-dist {
221
			font-size: 10px;
222
			color: #60a5fa;
223
			font-weight: 500;
224
		}
225
 
226
		/* Day Summary */
227
		.day-summary {
228
			font-size: 11px;
229
			color: #94a3b8;
230
			padding: 4px 8px;
231
			margin-left: 12px;
232
		}
233
 
234
		/* Calendar */
235
		.cal-grid {
236
			width: 100%;
237
			border-collapse: collapse;
238
		}
239
 
240
		.cal-grid th {
241
			padding: 6px;
242
			font-size: 11px;
243
			color: #64748b;
244
			text-align: center;
245
		}
246
 
247
		.cal-grid td {
248
			padding: 4px;
249
			text-align: center;
250
			font-size: 12px;
251
			height: 70px;
252
			vertical-align: top;
253
			border: 1px solid #334155;
254
			position: relative;
255
			cursor: pointer;
256
		}
257
 
258
		.cal-grid td:hover {
259
			background: #1e293b;
260
		}
261
 
262
		.cal-grid td.blocked {
263
			background: #0f172a;
264
			color: #475569;
265
			cursor: not-allowed;
266
		}
267
 
268
		.cal-grid td.holiday {
269
			background: #422006;
270
		}
271
 
272
		.cal-grid td.today {
273
			border: 2px solid #3b82f6;
274
		}
275
 
276
		.cal-date {
277
			font-weight: 600;
278
			margin-bottom: 2px;
279
		}
280
 
281
		.cal-chip {
282
			display: block;
283
			font-size: 9px;
284
			padding: 1px 4px;
285
			border-radius: 3px;
286
			color: #fff;
287
			margin: 1px 0;
288
			white-space: nowrap;
289
			overflow: hidden;
290
			text-overflow: ellipsis;
291
		}
292
 
293
		.cal-chip.running {
294
			box-shadow: 0 0 0 2px #ef4444;
295
		}
296
 
297
		.cal-chip.completed {
298
			opacity: 0.4;
299
		}
300
 
301
		.cal-holiday-label {
302
			font-size: 9px;
303
			color: #fbbf24;
304
		}
305
 
306
		/* Beat Cards in Calendar Panel */
307
		.beat-card {
308
			padding: 10px;
309
			margin-bottom: 8px;
310
			border-radius: 8px;
311
			border: 1px solid #334155;
312
			cursor: pointer;
313
			transition: all 0.2s;
314
		}
315
 
316
		.beat-card:hover {
317
			border-color: #60a5fa;
318
		}
319
 
320
		.beat-card.selected {
321
			border-color: #3b82f6;
322
			box-shadow: 0 0 0 1px #3b82f6;
323
		}
324
 
325
		.beat-card .beat-name {
326
			font-weight: 600;
327
			font-size: 13px;
328
			display: flex;
329
			align-items: center;
330
			gap: 6px;
331
		}
332
 
333
		.beat-card .beat-meta {
334
			font-size: 11px;
335
			color: #64748b;
336
			margin-top: 4px;
337
		}
338
 
339
		.beat-card .beat-actions {
340
			margin-top: 8px;
341
			display: flex;
342
			gap: 6px;
343
		}
344
 
345
		.beat-card .btn-sm {
346
			font-size: 11px;
347
			padding: 3px 8px;
348
			border-radius: 4px;
349
			border: none;
350
			cursor: pointer;
351
			font-weight: 500;
352
		}
353
 
354
		.btn-schedule {
355
			background: #3b82f6;
356
			color: #fff;
357
		}
358
 
359
		.btn-repeat {
360
			background: #22c55e;
361
			color: #fff;
362
		}
363
 
364
		.btn-schedule:hover {
365
			background: #2563eb;
366
		}
367
 
368
		.btn-repeat:hover {
369
			background: #16a34a;
370
		}
371
 
372
		.status-badge {
373
			font-size: 10px;
374
			padding: 2px 6px;
375
			border-radius: 10px;
376
			font-weight: 600;
377
		}
378
 
379
		.status-running {
380
			background: #ef4444;
381
			color: #fff;
382
		}
383
 
384
		.status-scheduled {
385
			background: #3b82f6;
386
			color: #fff;
387
		}
388
 
389
		.status-completed {
390
			background: #475569;
391
			color: #94a3b8;
392
		}
393
 
394
		/* Map */
395
		.map-container {
396
			flex: 1;
397
			position: relative;
398
		}
399
 
400
		#beat-map {
401
			width: 100%;
402
			height: 100%;
403
		}
404
 
405
		/* Bottom Bar */
406
		.bottom-bar {
407
			position: absolute;
408
			bottom: 0;
409
			left: 0;
410
			right: 0;
411
			display: flex;
412
			align-items: center;
413
			justify-content: space-between;
414
			padding: 8px 16px;
415
			background: rgba(15, 23, 42, 0.9);
416
			backdrop-filter: blur(8px);
417
			border-top: 1px solid #334155;
418
			font-size: 12px;
419
			z-index: 10;
420
		}
421
 
422
		.bottom-bar .day-info {
423
			display: flex;
424
			gap: 20px;
425
		}
426
 
427
		.progress-wrap {
428
			width: 200px;
429
			height: 8px;
430
			background: #334155;
431
			border-radius: 4px;
432
			overflow: hidden;
433
		}
434
 
435
		.progress-fill {
436
			height: 100%;
437
			border-radius: 4px;
438
			transition: width 0.3s;
439
		}
440
 
441
		/* Action Buttons */
442
		.bottom-bar .action-btns button {
443
			font-family: inherit;
444
			font-size: 12px;
445
			padding: 6px 14px;
446
			border-radius: 6px;
447
			border: none;
448
			cursor: pointer;
449
			font-weight: 500;
450
			margin-left: 8px;
451
		}
452
 
453
		.btn-end-day {
454
			background: #f59e0b;
455
			color: #0f172a;
456
		}
457
 
458
		.btn-finish {
459
			background: #22c55e;
460
			color: #fff;
461
		}
462
 
463
		.btn-end-day:hover {
464
			background: #d97706;
465
		}
466
 
467
		.btn-finish:hover {
468
			background: #16a34a;
469
		}
470
 
471
		/* Modal Overlay */
472
		.modal-overlay {
473
			display: none;
474
			position: fixed;
475
			top: 0;
476
			left: 0;
477
			right: 0;
478
			bottom: 0;
479
			background: rgba(0, 0, 0, 0.6);
480
			z-index: 100;
481
			justify-content: center;
482
			align-items: center;
483
		}
484
 
485
		.modal-overlay.show {
486
			display: flex;
487
		}
488
 
489
		.modal-box {
490
			background: #1e293b;
491
			border: 1px solid #334155;
492
			border-radius: 12px;
493
			padding: 24px;
494
			min-width: 400px;
495
			max-width: 600px;
496
			max-height: 80vh;
497
			overflow-y: auto;
498
		}
499
 
500
		.modal-box h3 {
501
			font-size: 16px;
502
			font-weight: 600;
503
			margin-bottom: 16px;
504
			color: #f1f5f9;
505
		}
506
 
507
		.modal-box input, .modal-box select {
508
			font-family: inherit;
509
			width: 100%;
510
			padding: 8px 12px;
511
			border: 1px solid #475569;
512
			border-radius: 6px;
513
			background: #0f172a;
514
			color: #e2e8f0;
515
			margin-bottom: 10px;
516
			font-size: 13px;
517
		}
518
 
519
		.modal-box .modal-actions {
520
			display: flex;
521
			justify-content: flex-end;
522
			gap: 8px;
523
			margin-top: 16px;
524
		}
525
 
526
		.modal-box .modal-actions button {
527
			font-family: inherit;
528
			padding: 8px 16px;
529
			border-radius: 6px;
530
			border: none;
531
			cursor: pointer;
532
			font-weight: 500;
533
			font-size: 13px;
534
		}
535
 
536
		.modal-cancel {
537
			background: #475569;
538
			color: #e2e8f0;
539
		}
540
 
541
		.modal-confirm {
542
			background: #3b82f6;
543
			color: #fff;
544
		}
545
 
546
		/* Info Window custom */
547
		.marker-popup {
548
			font-family: 'Inter', sans-serif;
549
			padding: 8px;
550
			min-width: 200px;
551
		}
552
 
553
		.marker-popup h4 {
554
			font-size: 13px;
555
			margin-bottom: 4px;
556
		}
557
 
558
		.marker-popup .popup-meta {
559
			font-size: 11px;
560
			color: #666;
561
			margin-bottom: 8px;
562
		}
563
 
564
		.marker-popup .popup-distance {
565
			font-size: 12px;
566
			font-weight: 500;
567
			color: #3b82f6;
568
			margin-bottom: 8px;
569
		}
570
 
571
		.marker-popup button {
572
			font-size: 11px;
573
			padding: 4px 10px;
574
			border: none;
575
			border-radius: 4px;
576
			cursor: pointer;
577
			margin-right: 4px;
578
			font-weight: 500;
579
		}
580
 
581
		.popup-next {
582
			background: #3b82f6;
583
			color: #fff;
584
		}
585
 
586
		.popup-last {
587
			background: #f59e0b;
588
			color: #0f172a;
589
		}
590
 
591
		.popup-nextday {
592
			background: #8b5cf6;
593
			color: #fff;
594
		}
595
 
596
		/* Nav Month */
597
		.month-nav {
598
			display: flex;
599
			align-items: center;
600
			gap: 12px;
601
			padding: 10px;
602
			border-bottom: 1px solid #334155;
603
		}
604
 
605
		.month-nav button {
606
			background: none;
607
			border: 1px solid #475569;
608
			color: #e2e8f0;
609
			padding: 4px 10px;
610
			border-radius: 4px;
611
			cursor: pointer;
612
			font-size: 12px;
613
		}
614
 
615
		.month-nav span {
616
			font-weight: 600;
617
			font-size: 14px;
618
		}
619
	</style>
620
</head>
621
<body>
622
 
623
<!-- Top Bar -->
624
<div class="top-bar">
625
	<h1>Route Planner</h1>
626
	<select id="bp-category" style="width:100px;">
627
		<option value="4">Sales</option>
628
	</select>
629
	<select id="bp-level" style="width:80px;">
630
		<option value="">Level</option>
631
		#foreach($et in $escalationTypes)
632
			<option value="$et">$et</option>
633
		#end
634
	</select>
635
	<select id="bp-auth-user" style="width:180px;">
636
		<option value="">Select User</option>
637
	</select>
638
	<button class="btn-primary" id="bp-load">Load</button>
639
	<div style="flex:1;"></div>
640
	<span id="bp-user-label" style="font-size:12px;color:#94a3b8;"></span>
641
</div>
642
 
643
<!-- Main Layout -->
644
<div class="main-layout">
645
	<!-- Left Panel -->
646
	<div class="left-panel">
647
		<div class="panel-tabs">
648
			<div class="panel-tab active" data-tab="route">Route</div>
649
			<div class="panel-tab" data-tab="calendar">Calendar</div>
650
		</div>
651
 
652
		<!-- Route Tab Content -->
653
		<div class="panel-content" id="panel-route">
654
			<div id="route-list">
655
				<p style="color:#64748b;font-size:12px;text-align:center;padding:40px 10px;">
656
					Select a user and click Load to start planning.
657
				</p>
658
			</div>
659
		</div>
660
 
661
		<!-- Calendar Tab Content -->
662
		<div class="panel-content" id="panel-calendar" style="display:none;">
663
			<div class="month-nav">
664
				<button id="cal-prev">&lt;</button>
665
				<span id="cal-month-label"></span>
666
				<button id="cal-next">&gt;</button>
667
			</div>
668
			<div id="cal-beat-cards"></div>
669
		</div>
670
	</div>
671
 
672
	<!-- Map -->
673
	<div class="map-container">
674
		<div id="beat-map"></div>
675
 
676
		<!-- Bottom Bar (on map) -->
677
		<div class="bottom-bar" id="bottom-bar" style="display:none;">
678
			<div class="day-info">
679
				<span id="bb-day-label">Day 1</span>
680
				<span id="bb-stops">0 stops</span>
681
				<span id="bb-distance">0 km</span>
682
				<span id="bb-time">0h 0m</span>
683
				<div class="progress-wrap">
684
					<div class="progress-fill" id="bb-progress" style="width:0%;background:#22c55e;"></div>
685
				</div>
686
			</div>
687
			<div class="action-btns">
688
				<button class="btn-end-day" id="btn-end-day">End Day</button>
689
				<button class="btn-finish" id="btn-finish">Finish Plan</button>
690
			</div>
691
		</div>
692
 
693
		<!-- Calendar Grid (overlays map when calendar tab active) -->
694
		<div id="cal-grid-container"
695
			 style="display:none;position:absolute;top:0;left:0;right:0;bottom:0;background:#0f172a;overflow-y:auto;padding:20px;">
696
			<div id="cal-grid-content"></div>
697
		</div>
698
	</div>
699
</div>
700
 
701
<!-- Home Location Modal -->
702
<div class="modal-overlay" id="modal-home">
703
	<div class="modal-box">
704
		<h3>Set Home Location</h3>
705
		<p style="font-size:12px;color:#94a3b8;margin-bottom:12px;">Search or click on map to set the auth user's
706
			home/base location.</p>
707
		<input type="text" id="home-search" placeholder="Search location...">
708
		<div id="home-map" style="height:250px;border-radius:8px;border:1px solid #334155;margin-bottom:12px;"></div>
709
		<div class="modal-actions">
710
			<button class="modal-cancel" id="home-cancel">Cancel</button>
711
			<button class="modal-confirm" id="home-confirm">Confirm Home</button>
712
		</div>
713
	</div>
714
</div>
715
 
716
<!-- Day Break Modal -->
717
<div class="modal-overlay" id="modal-daybreak">
718
	<div class="modal-box">
719
		<h3>End of Day</h3>
720
		<p id="daybreak-info" style="font-size:13px;margin-bottom:12px;"></p>
721
		<div style="margin-bottom:12px;">
722
			<label style="display:block;padding:8px;cursor:pointer;border-radius:6px;border:1px solid #334155;margin-bottom:6px;">
723
				<input type="radio" name="stay" value="HOME" checked> Go back home (base location)
724
			</label>
725
			<label style="display:block;padding:8px;cursor:pointer;border-radius:6px;border:1px solid #334155;">
726
				<input type="radio" name="stay" value="HOTEL"> Stay at hotel / other location
727
			</label>
728
		</div>
729
		<div id="hotel-fields" style="display:none;">
730
			<input type="text" id="hotel-search" placeholder="Search hotel/location...">
731
			<div id="hotel-map" style="height:200px;border-radius:8px;border:1px solid #334155;"></div>
732
		</div>
733
		<div class="modal-actions">
734
			<button class="modal-cancel" id="daybreak-cancel">Cancel</button>
735
			<button class="modal-confirm" id="daybreak-confirm">Continue to Next Day</button>
736
		</div>
737
	</div>
738
</div>
739
 
740
<!-- Calendar Schedule Modal -->
741
<div class="modal-overlay" id="modal-cal-schedule">
742
	<div class="modal-box" style="min-width:500px;">
743
		<h3 id="cal-sched-title">Schedule Beat</h3>
744
		<div id="cal-sched-grid"></div>
745
		<div id="cal-sched-info" style="font-size:12px;color:#94a3b8;margin-top:10px;"></div>
746
		<div class="modal-actions">
747
			<button class="modal-cancel" id="cal-sched-cancel">Cancel</button>
748
			<button class="modal-confirm" id="cal-sched-confirm">Confirm Schedule</button>
749
		</div>
750
	</div>
751
</div>
752
 
753
<script>
754
	var context = "${rc.contextPath}";
755
</script>
756
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAckO0y4Z6WhBOuMjNjioWLSYZDhGEvGBc&libraries=places&v=weekly"></script>
757
<script src="${rc.contextPath}/resources/js/beat-plan-app.js"></script>
758
</body>
759
</html>